<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>Philipe Fatio</title>
  <id>https://phili.pe/</id>
  <link href="https://phili.pe/"/>
  <link href="https://phili.pe/feed.xml" rel="self"/>
  <updated>2022-06-23T00:00:00Z</updated>
  <author>
    <name>Philipe Fatio</name>
  </author>
  <entry>
    <title>Git aliases supporting main and master</title>
    <summary>How to make your aliases agnostic to the default branch</summary>
    <link rel="alternate" type="text/html" href="https://phili.pe/posts/git-aliases-supporting-main-and-master/"/>
    <id>https://phili.pe/posts/git-aliases-supporting-main-and-master/</id>
    <published>2022-06-23T00:00:00Z</published>
    <updated>2022-06-27T19:52:25Z</updated>
    <author>
      <name>Philipe Fatio</name>
    </author>
    <content type="html">&lt;p&gt;More and more projects are moving or have moved from a default &lt;code&gt;master&lt;/code&gt; branch to one named &lt;code&gt;main&lt;/code&gt;. I deal with repos that use both. This means Git aliases that assume &lt;code&gt;master&lt;/code&gt; or &lt;code&gt;main&lt;/code&gt; break depending on the repo. With the help of a certain Git config these aliases can be made agnostic to the default branch.&lt;/p&gt;

&lt;p&gt;I use Git aliases quite &lt;a href="https://github.com/fphilipe/dotfiles/blob/58a60fadb4e6db0c7a131c1ad27031db90511f37/gitconfig#L3-L42"&gt;extensively&lt;/a&gt;. Some of the aliases involve the default branch. The one I use the most is &lt;code&gt;git com&lt;/code&gt; which was defined as follows:&lt;/p&gt;

&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[alias]
  com = switch master
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;(&lt;code&gt;com&lt;/code&gt; used to denote &lt;code&gt;CheckOut Master&lt;/code&gt; before &lt;code&gt;git switch&lt;/code&gt; existed.)&lt;/p&gt;

&lt;p&gt;Once I’ve started working on repos that use &lt;code&gt;main&lt;/code&gt; as the default branch, &lt;code&gt;git com&lt;/code&gt; no longer worked:&lt;/p&gt;

&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ git com
fatal: invalid reference: master
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;a href="https://lore.kernel.org/git/xmqq5za8hpir.fsf@gitster.c.googlers.com/"&gt;Git 2.28&lt;/a&gt; introduced a new config called &lt;code&gt;init.defaultBranch&lt;/code&gt; alongside a new warning when initializing a new repo:&lt;/p&gt;

&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ git init
hint: Using 'master' as the name for the initial branch. This default branch name
hint: is subject to change. To configure the initial branch name to use in all
hint: of your new repositories, which will suppress this warning, call:
hint:
hint:   git config --global init.defaultBranch &amp;lt;name&amp;gt;
hint:
hint: Names commonly chosen instead of 'master' are 'main', 'trunk' and
hint: 'development'. The just-created branch can be renamed via this command:
hint:
hint:   git branch -m &amp;lt;name&amp;gt;
Initialized empty Git repository in /Users/phil/foo/.git/
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;By now you might have come across this warning and set &lt;code&gt;init.defaultBranch&lt;/code&gt; globally to whichever value you prefer, e.g. &lt;code&gt;main&lt;/code&gt;:&lt;/p&gt;

&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git config --global init.defaultBranch main
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We can now change the alias to a shell script alias to (ab)use this value:&lt;/p&gt;

&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[alias]
  com = !git switch "$(git config init.defaultBranch)"
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This will read out the config from the repo and fall back to the global value if none is set. Because the repo doesn’t define &lt;code&gt;init.defaultBranch&lt;/code&gt;, it’ll return the global value &lt;code&gt;main&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Once we find ourselves in a new repo that doesn’t have a &lt;code&gt;main&lt;/code&gt; branch and instead uses a &lt;code&gt;master&lt;/code&gt; branch, the command will fail:&lt;/p&gt;

&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ git com
fatal: invalid reference: main
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;That makes sense, the global config is set to &lt;code&gt;main&lt;/code&gt;, but the repo uses &lt;code&gt;master&lt;/code&gt; as the default branch&lt;sup id="fnref:default-branch"&gt;&lt;a href="#fn:default-branch" class="footnote"&gt;1&lt;/a&gt;&lt;/sup&gt;. All we need to do now is to set the config &lt;code&gt;init.defaultBranch&lt;/code&gt; to &lt;code&gt;master&lt;/code&gt; &lt;em&gt;for the current repo&lt;/em&gt;, i.e. without the &lt;code&gt;--global&lt;/code&gt; flag:&lt;/p&gt;

&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git config init.defaultBranch master
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Repeating the command now succeeds:&lt;/p&gt;

&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ git com
Switched to branch 'master'
&lt;/code&gt;&lt;/pre&gt;

&lt;hr /&gt;

&lt;p&gt;This approach has worked well for me. When working on a new repo that deviates from my preferred initial branch, as soon as I hit the first error related to the default branch, I simply run one command that is already in my shell history and all my aliases work again.&lt;/p&gt;

&lt;p&gt;If you liked this post, you might also like my other post &lt;a href="/posts/configuring-git-for-work/"&gt;Configuring Git for work&lt;/a&gt;.&lt;/p&gt;
&lt;div class="footnotes"&gt;
  &lt;ol&gt;
    &lt;li id="fn:default-branch"&gt;
      &lt;p&gt;Git doesn’t really have a concept of a default branch except in the exact moment of initializing a new repo where the global config &lt;code&gt;init.defaultBranch&lt;/code&gt; is respected. &lt;code&gt;main&lt;/code&gt; or &lt;code&gt;master&lt;/code&gt; aren’t in any way special; they’re just branches like any other. &lt;a href="#fnref:default-branch" class="reversefootnote"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
  &lt;/ol&gt;
&lt;/div&gt;
</content>
  </entry>
  <entry>
    <title>Grep one-liners as CI tasks</title>
    <summary>Leveraging grep's exit status and output for simple code checks</summary>
    <link rel="alternate" type="text/html" href="https://phili.pe/posts/using-grep-for-simple-ci-tasks/"/>
    <id>https://phili.pe/posts/using-grep-for-simple-ci-tasks/</id>
    <published>2022-01-08T00:00:00Z</published>
    <updated>2022-01-08T12:11:45Z</updated>
    <author>
      <name>Philipe Fatio</name>
    </author>
    <content type="html">&lt;p&gt;The ubiquitous &lt;code&gt;grep&lt;/code&gt; utility can go a long way in enforcing simple rules in a codebase. Plenty of options and readable output combined with a smart exit status allow for simple one-liners in your continuous integration setup that are easy to write and maintain.&lt;/p&gt;

&lt;p&gt;The other day my team encountered an issue that we wanted to prevent via a CI task. We needed a quick way to ensure that our automated Android release builds would not contain any missing translations. These are typically stored in &lt;code&gt;strings.xml&lt;/code&gt; files using &lt;code&gt;&amp;lt;string&amp;gt;&lt;/code&gt; XML tags.&lt;/p&gt;

&lt;p&gt;This &lt;code&gt;grep&lt;/code&gt; command was all we needed to quickly&lt;sup id="fnref:ripgrep"&gt;&lt;a href="#fn:ripgrep" class="footnote"&gt;1&lt;/a&gt;&lt;/sup&gt; find such offenses:&lt;/p&gt;

&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ grep --recursive --line-number --include=strings.xml '&amp;gt;\(""\| *\)&amp;lt;/string&amp;gt;$'
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The output reads rather nicely and tells us precisely where the offenses are, also thanks to the additional &lt;code&gt;--line-number&lt;/code&gt; option:&lt;/p&gt;

&lt;pre class="highlight plaintext"&gt;&lt;code&gt;./app/src/main/res/values/strings.xml:23:    &amp;lt;string name="some_key"&amp;gt;&amp;lt;/string&amp;gt;
./app/src/main/res/values-fr/strings.xml:147:    &amp;lt;string name="another_key"&amp;gt;""&amp;lt;/string&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;A cool thing about &lt;code&gt;grep&lt;/code&gt; is that it has a smart exit status. From &lt;a href="https://www.gnu.org/software/grep/manual/grep.html#Exit-Status"&gt;GNU grep’s man page&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Normally the exit status is 0 if a line is selected, 1 if no lines were selected, and 2 if an error occurred.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Thus, as long as we have offenses we get an exit status &lt;code&gt;0&lt;/code&gt;, denoting success. Once we fix the offenses no lines will be matched by &lt;code&gt;grep&lt;/code&gt; and the exit status will be &lt;code&gt;1&lt;/code&gt;, denoting that it was unsuccessful.&lt;/p&gt;

&lt;p&gt;Since we want to fail the CI task in our &lt;code&gt;grep&lt;/code&gt; one-liner, we need to invert this exit status. Thus, when no offenses are found, we need to exit with &lt;code&gt;0&lt;/code&gt;, otherwise with &lt;code&gt;1&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Shell script allows a pipeline of one or more commands such as &lt;code&gt;cmdA&lt;/code&gt; or &lt;code&gt;cmdA | cmdB&lt;/code&gt; to be prefixed with a &lt;code&gt;!&lt;/code&gt; (followed by a space), i.e. &lt;code&gt;! cmdA&lt;/code&gt; or &lt;code&gt;! cmdA | cmdB&lt;/code&gt;. This alters the exit status as described in the &lt;a href="https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_09_02"&gt;Shell Command Language reference&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;If the pipeline does not begin with the &lt;code&gt;!&lt;/code&gt; reserved word, the exit status shall be the exit status of the last command specified in the pipeline. Otherwise, the exit status shall be the logical NOT of the exit status of the last command. That is, if the last command returns zero, the exit status shall be 1; if the last command returns greater than zero, the exit status shall be zero.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Thus, to get the desired inverted exit status for our CI task we just need to prefix &lt;code&gt;grep&lt;/code&gt; with &lt;code&gt;!&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;If we want to additionally print a success message when no offenses where found, we can do so with an &lt;code&gt;echo "message"&lt;/code&gt; which we combine with a logical &lt;code&gt;&amp;amp;&amp;amp;&lt;/code&gt; operator.&lt;/p&gt;

&lt;p&gt;Equipped with this knowledge, we conclude with a generic one-liner that &lt;strong&gt;fails the task in case offenses are found and prints a success message otherwise&lt;/strong&gt;:&lt;/p&gt;

&lt;pre class="highlight plaintext"&gt;&lt;code&gt;! grep [option...] [patterns] [file...] &amp;amp;&amp;amp; echo "No offenses found"
&lt;/code&gt;&lt;/pre&gt;
&lt;div class="footnotes"&gt;
  &lt;ol&gt;
    &lt;li id="fn:ripgrep"&gt;
      &lt;p&gt;I personally prefer &lt;a href="https://github.com/BurntSushi/ripgrep"&gt;ripgrep&lt;/a&gt; as it is much faster than &lt;code&gt;grep&lt;/code&gt;, but usually that is not available on CI machines. &lt;a href="#fnref:ripgrep" class="reversefootnote"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
  &lt;/ol&gt;
&lt;/div&gt;
</content>
  </entry>
  <entry>
    <title>Configuring Git for Work</title>
    <summary>How to use your work email in your work repositories</summary>
    <link rel="alternate" type="text/html" href="https://phili.pe/posts/configuring-git-for-work/"/>
    <id>https://phili.pe/posts/configuring-git-for-work/</id>
    <published>2020-11-17T00:00:00Z</published>
    <updated>2020-11-17T20:38:04Z</updated>
    <author>
      <name>Philipe Fatio</name>
    </author>
    <content type="html">&lt;p&gt;You can override your globally configured email inside individual repositories, allowing you to use your work email for work-related repos. Setting this up for each repo—and remembering to do so—is cumbersome. Luckily, there is an easier way to accomplish this for all repos within a certain directory.&lt;/p&gt;

&lt;p&gt;One of the first things you did when you set up Git was to configure your name and email:&lt;/p&gt;

&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ git config --global user.name "Jane Doe"
$ git config --global user.email jane@mail.com
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The above commands added the following lines to your global Git configuration file &lt;code&gt;~/.gitconfig&lt;/code&gt;:&lt;/p&gt;

&lt;pre class="highlight ini"&gt;&lt;code&gt;&lt;span class="nn"&gt;[user]&lt;/span&gt;
	&lt;span class="py"&gt;name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;Jane Doe&lt;/span&gt;
	&lt;span class="py"&gt;email&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;jane@mail.com&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Each repository also has its own Git configuration located at &lt;code&gt;.git/config&lt;/code&gt;. Configs in the local file take precedence over the global configs.&lt;/p&gt;

&lt;p&gt;You can set configs in &lt;code&gt;.git/config&lt;/code&gt; manually or by passing the &lt;code&gt;--local&lt;/code&gt; flag to &lt;code&gt;git config&lt;/code&gt;. Thus, if I want to use my work email in a specific repo, I need to set it as follows:&lt;/p&gt;

&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ git config --local user.email doe@acme.org
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;If you want to do this for all work repos, it gets a bit cumbersome. Above all, it’s easy to forget to do this for repos that you’ll clone or create in the future.&lt;/p&gt;

&lt;p&gt;Fortunately, Git has a more scalable approach to this problem. You can &lt;strong&gt;conditionally&lt;/strong&gt; include further Git config files based on the directory of a Git repo.&lt;/p&gt;

&lt;p&gt;Let’s assume that all my work-related repos are inside the folder &lt;code&gt;~/Documents/Acme/repos/&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;First, I’ll create a separate Git config file &lt;code&gt;~/.gitconfig-work&lt;/code&gt; that contains my work-related overrides:&lt;/p&gt;

&lt;pre class="highlight ini"&gt;&lt;code&gt;&lt;span class="nn"&gt;[user]&lt;/span&gt;
	&lt;span class="py"&gt;email&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;doe@acme.org&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Then, I include this file from my global Git config file in &lt;code&gt;~/.gitconfig&lt;/code&gt;:&lt;/p&gt;

&lt;pre class="highlight ini"&gt;&lt;code&gt;&lt;span class="nn"&gt;[includeIf "gitdir:~/Documents/Acme/repos"]&lt;/span&gt;
	&lt;span class="py"&gt;path&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;.gitconfig-work&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;It’s important to place above snippet &lt;strong&gt;at the end&lt;/strong&gt; of your &lt;code&gt;~/.gitconfig&lt;/code&gt; file because, according to the &lt;a href="https://git-scm.com/docs/git-config"&gt;documentation on git-config&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;The contents of the included file are inserted immediately, as if they had been found at the location of the include directive.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If we were to restructure our work directory, e.g. by changing &lt;code&gt;Acme&lt;/code&gt; to &lt;code&gt;acme&lt;/code&gt; or by moving the repositories somewhere else, such as to &lt;code&gt;~/repos/acme/&lt;/code&gt;, the include directive would no longer apply. My newly created commits would now use my globally defined private email rather than my work email. Most likely, I wouldn’t even notice.&lt;/p&gt;

&lt;p&gt;To prevent this from happening, we can generalize the path used in the include directive above. First, we can use &lt;code&gt;gitdir/i&lt;/code&gt; to perform the matching case-insensitively. Further, there are a few assumptions around the path that can help us. From the &lt;a href="https://git-scm.com/docs/git-config"&gt;docs&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;ul&gt;
    &lt;li&gt;
      &lt;p&gt;If the pattern does not start with either &lt;code&gt;~/&lt;/code&gt;, &lt;code&gt;./&lt;/code&gt; or &lt;code&gt;/&lt;/code&gt;, &lt;code&gt;**/&lt;/code&gt; will be automatically prepended. For example, the pattern &lt;code&gt;foo/bar&lt;/code&gt; becomes &lt;code&gt;**/foo/bar&lt;/code&gt; and would match &lt;code&gt;/any/path/to/foo/bar&lt;/code&gt;.&lt;/p&gt;
    &lt;/li&gt;
    &lt;li&gt;
      &lt;p&gt;If the pattern ends with &lt;code&gt;/&lt;/code&gt;, &lt;code&gt;**&lt;/code&gt; will be automatically added. For example, the pattern &lt;code&gt;foo/&lt;/code&gt; becomes &lt;code&gt;foo/**&lt;/code&gt;. In other words, it matches “foo” and everything inside, recursively.&lt;/p&gt;
    &lt;/li&gt;
  &lt;/ul&gt;
&lt;/blockquote&gt;

&lt;p&gt;Equipped with this knowledge, we can generalize the include directive so that it applies to any Git repository that is nested within a folder named after my company—case-insensitively, mind you:&lt;/p&gt;

&lt;pre class="highlight ini"&gt;&lt;code&gt;&lt;span class="nn"&gt;[includeIf "gitdir/i:acme/"]&lt;/span&gt;
	&lt;span class="py"&gt;path&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;.gitconfig-work&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;To verify that this is working, I can look up the resolved config value in a specific repo:&lt;/p&gt;

&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ cd ~/repos/private/my-project
$ git config user.email
jane@mail.com

$ cd ~/Documents/Acme/repos/website
$ git config user.email
doe@acme.org
&lt;/code&gt;&lt;/pre&gt;

&lt;hr /&gt;

&lt;p&gt;I encourage you to check out the &lt;a href="https://git-scm.com/docs/git-config"&gt;git-config manual&lt;/a&gt; (&lt;code&gt;git help config&lt;/code&gt;). You’ll find some interesting things in there. For instance, an include directive can be conditional on the branch you’re currently on.&lt;/p&gt;

</content>
  </entry>
  <entry>
    <title>Is There a Better Way?</title>
    <summary>The question to keep asking yourself when using your tools</summary>
    <link rel="alternate" type="text/html" href="https://phili.pe/posts/is-there-a-better-way/"/>
    <id>https://phili.pe/posts/is-there-a-better-way/</id>
    <published>2020-02-02T00:00:00Z</published>
    <updated>2020-10-20T12:15:56Z</updated>
    <author>
      <name>Philipe Fatio</name>
    </author>
    <content type="html">&lt;p&gt;A lot of the tasks we perform on a computer are repetitive and come with a cognitive load. Minimizing this repetitiveness helps us stay focused and accomplish our tasks quicker. As developers, our main tools to get the job done are the OS, the browser, our editor of choice, and the terminal. Investing in those and molding them to your needs pays off.&lt;/p&gt;

&lt;p&gt;As someone who spends most of their workday in front of a computer, I like to reduce visual clutter and to optimize workflows. For that reason, I’ve customized my computer and tools to suit me, from keyboard shortcuts, to simplifying the UI, up to customizing touchpad gestures.&lt;/p&gt;

&lt;p&gt;This is the result of a constant, but passive, pursuit over the years for doing things in an easier, quicker, and mentally less taxing way. When repeating a task for a few times that I find too tedious, I tell myself: &lt;em&gt;there must be a better way!&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;When observing other computer users, I’m often astounded how little they deviate from the typical point-and-click mode of using a computer—especially for peer developers. This goes from the simplest action such as switching apps, where they reach for the mouse to click on an icon in the dock, to more advanced tasks such as editing and navigating text where they only ever change or jump one character at a time.&lt;/p&gt;

&lt;p&gt;In the following I’ll list a few examples I’ve observed others do over the years and how to—I believe—do it better. I understand that these suggestions might be opinionated and I don’t expect you to agree with me. Nonetheless, I hope this will motivate you to refine your workflow and hone your skills in using your tools.&lt;/p&gt;

&lt;h2 class="no_toc" id="table-of-contents"&gt;Table of Contents&lt;/h2&gt;

&lt;ul id="markdown-toc"&gt;
  &lt;li&gt;&lt;a id="markdown-toc-macos" href="#macos"&gt;macOS&lt;/a&gt;    &lt;ul&gt;
      &lt;li&gt;&lt;a id="markdown-toc-menu-items-and-keyboard-shortcuts" href="#menu-items-and-keyboard-shortcuts"&gt;Menu Items and Keyboard Shortcuts&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a id="markdown-toc-switching-apps-and-windows" href="#switching-apps-and-windows"&gt;Switching Apps and Windows&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a id="markdown-toc-window-manager" href="#window-manager"&gt;Window Manager&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a id="markdown-toc-hiding-unused-ui" href="#hiding-unused-ui"&gt;Hiding Unused UI&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a id="markdown-toc-cursor-movement-and-text-selection" href="#cursor-movement-and-text-selection"&gt;Cursor Movement and Text Selection&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a id="markdown-toc-clipboard-history" href="#clipboard-history"&gt;Clipboard History&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;a id="markdown-toc-web-browsing" href="#web-browsing"&gt;Web Browsing&lt;/a&gt;    &lt;ul&gt;
      &lt;li&gt;&lt;a id="markdown-toc-the-power-of-bookmarks" href="#the-power-of-bookmarks"&gt;The Power of Bookmarks&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a id="markdown-toc-predictable-urls" href="#predictable-urls"&gt;Predictable URLs&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;a id="markdown-toc-text-editors" href="#text-editors"&gt;Text Editors&lt;/a&gt;    &lt;ul&gt;
      &lt;li&gt;&lt;a id="markdown-toc-jump-to-file" href="#jump-to-file"&gt;Jump to File&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a id="markdown-toc-line-wise-editing" href="#line-wise-editing"&gt;Line-wise Editing&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;a id="markdown-toc-terminal" href="#terminal"&gt;Terminal&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a id="markdown-toc-touch-typing" href="#touch-typing"&gt;Touch-typing&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id="macos"&gt;macOS&lt;/h2&gt;

&lt;p&gt;I’m a mac user and thus these examples and tips are specific to macOS. Nonetheless, the ideas behind them may apply to other OSs as well.&lt;/p&gt;

&lt;h3 id="menu-items-and-keyboard-shortcuts"&gt;Menu Items and Keyboard Shortcuts&lt;/h3&gt;

&lt;p&gt;I’m always surprised when I see a fellow developer grab their mouse to click on one of the typical menu items for which there is a keyboard shortcut. New File (&lt;kbd class="macos"&gt;⌘N&lt;/kbd&gt;), Save (&lt;kbd class="macos"&gt;⌘S&lt;/kbd&gt;), New Tab (&lt;kbd class="macos"&gt;⌘T&lt;/kbd&gt;), Close (&lt;kbd class="macos"&gt;⌘W&lt;/kbd&gt;), Quit (&lt;kbd class="macos"&gt;⌘Q&lt;/kbd&gt;), Preferences (&lt;kbd class="macos"&gt;⌘,&lt;/kbd&gt;), these are all typically bound to the same keyboard shortcut across apps.&lt;/p&gt;

&lt;p&gt;There’s no excuse not to memorize them. The menu even shows us the shortcut for the item:&lt;/p&gt;

&lt;p&gt;&lt;img alt="Menu item keyboard shortcut" width="600" height="270" src="menu-item.png" /&gt;&lt;/p&gt;

&lt;p&gt;If you want to get more out of the menu, macOS has a few tricks up its sleeve.&lt;/p&gt;

&lt;p&gt;Sometimes you forget the shortcut for a particular menu item. Maybe you even forgot where that particular menu item is or you don’t even know whether a menu item for doing a certain action exists. This is where the Help menu comes in handy.&lt;/p&gt;

&lt;p&gt;Suppose I’m in a graphics editor and I want to change a mask to use its alpha channel for masking. Opening the Help menu item and typing &lt;kbd&gt;alpha&lt;/kbd&gt; will show me where the menu item is. I can also launch it conveniently from there by hitting return.&lt;/p&gt;

&lt;p&gt;&lt;img alt="Help menu" width="1160" height="537" src="help-menu.png" /&gt;&lt;/p&gt;

&lt;p&gt;You can focus this search field in the Help menu item with &lt;kbd class="macos"&gt;⇧⌘?&lt;/kbd&gt;, effectively turning it into a mini launcher for menu items.&lt;/p&gt;

&lt;p&gt;If you find yourself using the same menu item often, but that specific item doesn’t have a keyboard shortcut assigned to it, you can assign a custom one. This can be done in System Preferences in the Keyboard pane under the Shortcuts tab. Select App Shortcuts in the list and press the plus button. Now you can select the app, enter the menu item title for which you want to add a shortcut, and finally specify the shortcut. That menu item will now show your custom shortcut.&lt;/p&gt;

&lt;p&gt;&lt;img alt="Adding app-specific keyboard shortcuts" width="780" height="693" src="app-shortcuts.png" /&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://support.apple.com/en-us/HT201236"&gt;Here&lt;/a&gt; you can find an official and extensive list of generic macOS keyboard shortcut.&lt;/p&gt;

&lt;h3 id="switching-apps-and-windows"&gt;Switching Apps and Windows&lt;/h3&gt;

&lt;p&gt;One way of switching between windows and apps that I’ve seen people do surprisingly often is to move the topmost window slightly to the side in order to reach the window behind. The next best way is to click on an icon in the Dock, which brings to front the desired app, but not necessarily the desired window in case the app has multiple.&lt;/p&gt;

&lt;p&gt;When I started using a Mac, I was a big fan of Exposé and Hot Corners. I still have my top right screen corner set to trigger Exposé for all apps and the top left corner set to Exposé for the current app. When I’m in mouse mode, that’s a great way to switch apps and windows.&lt;/p&gt;

&lt;p&gt;Mostly I’m in keyboard mode though where I use &lt;kbd class="macos"&gt;⌘⇥&lt;/kbd&gt;, i.e. &lt;kbd&gt;Command&lt;/kbd&gt;-&lt;kbd&gt;Tab&lt;/kbd&gt;, to switch apps. If you keep &lt;kbd&gt;Command&lt;/kbd&gt; pressed after hitting &lt;kbd&gt;Tab&lt;/kbd&gt;, the app switcher will stay visible:&lt;/p&gt;

&lt;p&gt;&lt;img src="app-switcher.png" width="972" height="186" /&gt;&lt;/p&gt;

&lt;p&gt;Pressing &lt;kbd&gt;Tab&lt;/kbd&gt; again moves the selection to the next app. Releasing &lt;kbd&gt;Command&lt;/kbd&gt; will bring that app to foreground.&lt;/p&gt;

&lt;p&gt;To move the selection to the left, hit the key &lt;kbd&gt;&amp;#96;&lt;/kbd&gt; (backtick) key located above &lt;kbd&gt;Tab&lt;/kbd&gt; (or use the left arrow).&lt;/p&gt;

&lt;p&gt;While the switcher is open, you can also quit or hide the highlighted app by hitting &lt;kbd&gt;Q&lt;/kbd&gt; or &lt;kbd&gt;H&lt;/kbd&gt;, respectively.&lt;/p&gt;

&lt;p&gt;A key feature of the app switcher is that the apps are ordered by recency. Let’s say you’re composing an email in Mail. You might need to look something up in Safari so you hold &lt;kbd&gt;Command&lt;/kbd&gt; followed by the number of &lt;kbd&gt;Tab&lt;/kbd&gt; strokes required to select Safari. Mail is now located after Safari in the app switcher. Thus, to jump back to Mail, a single &lt;kbd class="macos"&gt;⌘⇥&lt;/kbd&gt; will take you there. This is so quick that the switcher won’t even show. Now Safari will be in second position, such that repeated &lt;kbd class="macos"&gt;⌘⇥&lt;/kbd&gt; strokes cause you to cycle between Mail and Safari.&lt;/p&gt;

&lt;p&gt;Switching between windows of the current app is similar. In Mail you might need to switch between the compose window and the mailbox window. You can cycle between the windows using &lt;kbd class="macos"&gt;⌘&amp;#96;&lt;/kbd&gt; (&lt;kbd class="macos"&gt;⇧⌘&amp;#96;&lt;/kbd&gt; in the reverse direction).&lt;/p&gt;

&lt;h3 id="window-manager"&gt;Window Manager&lt;/h3&gt;

&lt;p&gt;Fiddling with windows to move or resize them is another thing where I’ve told myself a long time ago that there must be a better way. The process of grabbing a window, moving it to a corner of the screen then dragging its opposite corner to resize it in order to maximize a window is as cumbersome as it can get. Another use case I see often is placing two windows side by side.&lt;/p&gt;

&lt;p&gt;This is where a window manager comes in handy, which conveniently turns these manipulations into single clicks or key strokes. No more fiddling with windows and their edges.&lt;/p&gt;

&lt;p&gt;There’s quite a few such window managers available for macOS. I started with &lt;a href="http://www.irradiatedsoftware.com/sizeup/"&gt;SizeUp&lt;/a&gt; ten years ago, which worked great, but soon after switched to &lt;a href="https://github.com/jigish/slate"&gt;Slate&lt;/a&gt;, which offers more customizability and has some additional features. Slate barely has any UI, but is highly customizable using a text based config file (here’s &lt;a href="https://github.com/fphilipe/dotfiles/blob/master/slate"&gt;mine&lt;/a&gt; in case you’re curious).&lt;/p&gt;

&lt;p&gt;The typical things that I do with a window:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;maximize with &lt;kbd class="macos"&gt;⌃⌥⌘M&lt;/kbd&gt;&lt;/li&gt;
  &lt;li&gt;center with &lt;kbd class="macos"&gt;⌃⌥⌘C&lt;/kbd&gt;, which causes the window to use ⅔ of the screen width and full screen height, useful for websites that don’t work well when too wide&lt;/li&gt;
  &lt;li&gt;resize to the left half of the screen with &lt;kbd class="macos"&gt;⌃⌥⌘H&lt;/kbd&gt;&lt;/li&gt;
  &lt;li&gt;resize to the right half of the screen with &lt;kbd class="macos"&gt;⌃⌥⌘L&lt;/kbd&gt;&lt;/li&gt;
  &lt;li&gt;resize to the lower half of the screen with &lt;kbd class="macos"&gt;⌃⌥⌘J&lt;/kbd&gt;&lt;/li&gt;
  &lt;li&gt;resize to the upper half of the screen with &lt;kbd class="macos"&gt;⌃⌥⌘K&lt;/kbd&gt;&lt;/li&gt;
  &lt;li&gt;throw the window to the next screen with &lt;kbd class="macos"&gt;⌃⌥⌘N&lt;/kbd&gt; when connected to more than one monitor&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id="hiding-unused-ui"&gt;Hiding Unused UI&lt;/h3&gt;

&lt;p&gt;When looking at other people’s screen, I often wonder if the buttons present in the UI of apps they use are ever pressed by them. Apps by default come with a toolbar full of buttons, some more useful than others. In my opinion these clutter the UI unnecessarily, especially if you never press them.&lt;/p&gt;

&lt;p&gt;For that reason, I like to customize the UI of the apps I use most. One such app is Mail. Except for browsing messages, I do most of the actions using keyboard shortcuts. For that reason, I don’t need any of the buttons in the toolbar that are shown by default.&lt;/p&gt;

&lt;p&gt;&lt;img src="mail-default-toolbar.png" width="1007" height="152" /&gt;&lt;/p&gt;

&lt;p&gt;I have removed every item in the toolbar except for the search field. Since the search field is only used occasionally, I also hide the toolbar entirely. I can focus the search field by pressing &lt;kbd class="macos"&gt;⌥⌘F&lt;/kbd&gt;, which will reveal the toolbar temporarily until I clear the search.&lt;/p&gt;

&lt;p&gt;&lt;img src="mail.png" width="941" height="661" /&gt;&lt;/p&gt;

&lt;p&gt;The compose window is similar. The default comes with plenty of buttons that I don’t need.&lt;/p&gt;

&lt;p&gt;&lt;img src="mail-default-compose-toolbar.png" width="1007" height="152" /&gt;&lt;/p&gt;

&lt;p&gt;All I want is an experience reduced to the max so I can focus on the message.&lt;/p&gt;

&lt;p&gt;&lt;img src="mail-compose.png" width="746" height="532" /&gt;&lt;/p&gt;

&lt;p&gt;If I want to make something bold or italic, I hit &lt;kbd class="macos"&gt;⌘B&lt;/kbd&gt; or &lt;kbd class="macos"&gt;⌘I&lt;/kbd&gt;, respectively (these pretty much work globally on macOS). If I need a bullet list or a numbered list, I have my custom keyboard shortcuts &lt;kbd class="macos"&gt;⇧⌘B&lt;/kbd&gt; and &lt;kbd class="macos"&gt;⇧⌘1&lt;/kbd&gt; for the respective menu items (see &lt;a href="#menu-items-and-keyboard-shortcuts"&gt;section above&lt;/a&gt; on how to add custom shortcuts).&lt;/p&gt;

&lt;p&gt;Once I’m ready to send the message off, I hit &lt;kbd class="macos"&gt;⇧⌘D&lt;/kbd&gt; (D as in deliver).&lt;/p&gt;

&lt;h3 id="cursor-movement-and-text-selection"&gt;Cursor Movement and Text Selection&lt;/h3&gt;

&lt;p&gt;Countless times I’ve noticed that people don’t realize that there are more advanced ways to move the cursor in a text field or to select text than doing so character by character. It’s almost agonizing to see someone move their cursor by holding down &lt;kbd class="macos"&gt;←&lt;/kbd&gt; or &lt;kbd class="macos"&gt;→&lt;/kbd&gt; for several seconds (if only they’d at least increase the key repeat rate) or to see them trying to select a word or range of words and missing a character or selecting one to many.&lt;/p&gt;

&lt;p&gt;Selecting a single word is as simple as double-clicking it. To select a range of words, select either the first or last word by double-clicking it, then click the word on the other end of the range while holding down &lt;kbd&gt;Shift&lt;/kbd&gt;. The following video demonstrates this:&lt;/p&gt;

&lt;video src="text-word-selection.mp4" width="688" height="82" autoplay="" loop=""&gt;&lt;/video&gt;

&lt;p&gt;As you see, no need for surgical precision with your mouse.&lt;/p&gt;

&lt;p&gt;If you want to select an entire paragraph rather than a range of words, simply triple click on the paragraph.&lt;/p&gt;

&lt;p&gt;Similarly, moving your cursor in a text field can be done quicker than character by character. While holding down &lt;kbd&gt;Option&lt;/kbd&gt; you can press &lt;kbd class="macos"&gt;←&lt;/kbd&gt; and &lt;kbd class="macos"&gt;→&lt;/kbd&gt; to move word-wise. To move to the beginning or end of the line, use &lt;kbd class="macos"&gt;⌘←&lt;/kbd&gt; and &lt;kbd class="macos"&gt;⌘→&lt;/kbd&gt;. The up and down arrows can also be used: &lt;kbd class="macos"&gt;⌥↑&lt;/kbd&gt; and &lt;kbd class="macos"&gt;⌥↓&lt;/kbd&gt; allow you to move by paragraph while &lt;kbd class="macos"&gt;⌘↑&lt;/kbd&gt; and &lt;kbd class="macos"&gt;⌘↓&lt;/kbd&gt; move the cursor to the very beginning and end of the field, respectively.&lt;/p&gt;

&lt;p&gt;The above shortcuts can be combined with &lt;kbd&gt;Shift&lt;/kbd&gt; to select text rather than just move the cursor.&lt;/p&gt;

&lt;p&gt;&lt;kbd&gt;Option&lt;/kbd&gt; and &lt;kbd&gt;Command&lt;/kbd&gt; can also be combined with &lt;kbd&gt;Backspace&lt;/kbd&gt; (i.e. delete to the left) and &lt;kbd&gt;Delete&lt;/kbd&gt; (i.e. delete to the right): &lt;kbd class="macos"&gt;⌥⌫&lt;/kbd&gt; and &lt;kbd class="macos"&gt;⌥⌦&lt;/kbd&gt; delete the word to the left and right, respectively; &lt;kbd class="macos"&gt;⌘⌫&lt;/kbd&gt; and &lt;kbd class="macos"&gt;⌘⌦&lt;/kbd&gt; delete from the cursor position to the beginning and end of the line, respectively.&lt;/p&gt;

&lt;p&gt;These days I prefer the Emacs bindings that also work globally on macOS. The reason is that I use these extensively in the terminal (as described &lt;a href="#terminal"&gt;later&lt;/a&gt;) where above shortcuts don’t work. Additionally, they allow me to stay on the home row.&lt;/p&gt;

&lt;p&gt;The shortcuts are:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;kbd class="macos"&gt;⌃B&lt;/kbd&gt; (back) to move left instead of &lt;kbd class="macos"&gt;←&lt;/kbd&gt;&lt;/li&gt;
  &lt;li&gt;&lt;kbd class="macos"&gt;⌃F&lt;/kbd&gt; (forward) to move right instead of &lt;kbd class="macos"&gt;→&lt;/kbd&gt;&lt;/li&gt;
  &lt;li&gt;&lt;kbd class="macos"&gt;⌃P&lt;/kbd&gt; (previous) to move up instead of &lt;kbd class="macos"&gt;↑&lt;/kbd&gt;&lt;/li&gt;
  &lt;li&gt;&lt;kbd class="macos"&gt;⌃N&lt;/kbd&gt; (next) to move down instead of &lt;kbd class="macos"&gt;↓&lt;/kbd&gt;&lt;/li&gt;
  &lt;li&gt;&lt;kbd class="macos"&gt;⌃⌥B&lt;/kbd&gt; to move left word-wise instead of &lt;kbd class="macos"&gt;⌥←&lt;/kbd&gt;&lt;/li&gt;
  &lt;li&gt;&lt;kbd class="macos"&gt;⌃⌥F&lt;/kbd&gt; to move right word-wise instead of &lt;kbd class="macos"&gt;⌥→&lt;/kbd&gt;&lt;/li&gt;
  &lt;li&gt;&lt;kbd class="macos"&gt;⌃A&lt;/kbd&gt; to move to the beginning of the line (in contrast to &lt;kbd class="macos"&gt;⌘←&lt;/kbd&gt; it uses hard wraps as anchors, not soft wraps)&lt;/li&gt;
  &lt;li&gt;&lt;kbd class="macos"&gt;⌃E&lt;/kbd&gt; to move to the end of the line (in contrast to &lt;kbd class="macos"&gt;⌘→&lt;/kbd&gt; it uses hard wraps as anchors, not soft wraps)&lt;/li&gt;
  &lt;li&gt;&lt;kbd class="macos"&gt;⌃H&lt;/kbd&gt; to delete to the left instead of &lt;kbd class="macos"&gt;⌫&lt;/kbd&gt;&lt;/li&gt;
  &lt;li&gt;&lt;kbd class="macos"&gt;⌃D&lt;/kbd&gt; to delete to the right instead of &lt;kbd class="macos"&gt;⌦&lt;/kbd&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id="clipboard-history"&gt;Clipboard History&lt;/h3&gt;

&lt;p&gt;Quite often the need arises to copy two or more bits of text to another place. Unfortunately, the clipboard only holds one copied value at a time. Thus, you need to switch a few times between the app containing the bits to be copied and the app where you need to paste the information until you’ve transferred the data.&lt;/p&gt;

&lt;p&gt;This is where a clipboard history comes in handy. Instead of switching back and forth, copy the relevant parts, switch to the destination app, and retrieve the items from the clipboard history.&lt;/p&gt;

&lt;p&gt;I use &lt;a href="https://www.obdev.at/products/launchbar/index.html"&gt;LaunchBar&lt;/a&gt; as an app launcher—basically a Spotlight on steroids. It comes with many useful features, including a clipboard history. Here’s a short demo on how a clipboard history can make your life easier:&lt;/p&gt;

&lt;video src="clipboard-history.mp4" width="520" height="265" controls=""&gt;&lt;/video&gt;

&lt;p&gt;A clipboard history is so essential to my workflow today that I can’t imagine how I worked without one for so many years. I recommend it to colleagues whenever I see them copy-pasting multiple times between two apps, and that happens quite often.&lt;/p&gt;

&lt;h2 id="web-browsing"&gt;Web Browsing&lt;/h2&gt;

&lt;h3 id="the-power-of-bookmarks"&gt;The Power of Bookmarks&lt;/h3&gt;

&lt;p&gt;Navigating is the perfect example for reducing the number of steps to reach your goal. Countless times I’ve seen developers open &lt;a href="https://github.com/"&gt;github.com&lt;/a&gt; just to then search for a repository somewhere in a list, navigate to it, and then switching to the repository’s issues.&lt;/p&gt;

&lt;p&gt;I used to be that person until I stopped for a second to realize how tedious this is and how long it was taking me. A simple bookmark could take me there directly. Placing a bookmark in your browser’s new tab view gets you a long way.&lt;/p&gt;

&lt;p&gt;I’ve since taken this to another level. Now I have hierarchies of bookmarks for many services I use. For GitHub e.g. that would mean a GitHub folder with the pages and repos that I use regularly:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;GitHub
    &lt;ul&gt;
      &lt;li&gt;Assigned Issues&lt;/li&gt;
      &lt;li&gt;My Pull Requests&lt;/li&gt;
      &lt;li&gt;My Issues&lt;/li&gt;
      &lt;li&gt;Review Requests&lt;/li&gt;
      &lt;li&gt;Projects&lt;/li&gt;
      &lt;li&gt;organization/repo
        &lt;ul&gt;
          &lt;li&gt;Home&lt;/li&gt;
          &lt;li&gt;Issues&lt;/li&gt;
          &lt;li&gt;New Issue&lt;/li&gt;
          &lt;li&gt;Pull Requests&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
      &lt;li&gt;…&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I do the same for other services such as Basecamp or Trello.&lt;/p&gt;

&lt;p&gt;With &lt;a href="https://www.obdev.at/products/launchbar/index.html"&gt;LaunchBar&lt;/a&gt; I can quickly open any bookmark without even switching to the browser first. The hierarchy allows me to drill down to the bookmark I’m looking for in case I don’t remember its title, which is useful for pages that I access less often.&lt;/p&gt;

&lt;p&gt;It’s like navigating without waiting for the intermediate pages to load and without the clutter.&lt;/p&gt;

&lt;h3 id="predictable-urls"&gt;Predictable URLs&lt;/h3&gt;

&lt;p&gt;Navigating to URLs with predictable patterns is another area where a launcher can speed up things significantly. Let’s say you look up third party dependencies quite often. I do that e.g. for the Ruby language where a package is called a &lt;em&gt;gem&lt;/em&gt;. Instead of opening my browser and googling &lt;em&gt;rails gem&lt;/em&gt;, I’ve set up a search pattern in LaunchBar. I trigger LaunchBar, search for the RubyGems action by typing &lt;kbd&gt;gem&lt;/kbd&gt;, type in &lt;kbd&gt;rails&lt;/kbd&gt; and hit return, and &lt;a href="https://rubygems.org/gems/rails"&gt;https://rubygems.org/gems/rails&lt;/a&gt; opens in the browser.&lt;/p&gt;

&lt;video src="rails.mp4" poster="rails.png" controls=""&gt;&lt;/video&gt;

&lt;p&gt;This also works great for the search functionality of any website.&lt;/p&gt;

&lt;h2 id="text-editors"&gt;Text Editors&lt;/h2&gt;

&lt;p&gt;Many text editors and IDEs share a few fundamental features that are often even bound to the same keyboard shortcuts. I’d like to highlight two such features here that I’ve often seen neglected by other developers.&lt;/p&gt;

&lt;p&gt;Personally, I used to be a &lt;a href="https://macromates.com/"&gt;TextMate&lt;/a&gt; user until I switched to &lt;a href="https://www.vim.org/"&gt;Vim&lt;/a&gt; about eight years ago. With TextMate I did learn quite a lot of great features that, if I’m not mistaken, were copied or at least inspired similar features in other editors. Because of this and the fact that I still know most shortcuts by heart, I quickly find myself at home for basic editing and navigation in other editors.&lt;/p&gt;

&lt;h3 id="jump-to-file"&gt;Jump to File&lt;/h3&gt;

&lt;p&gt;Some developers like to navigate to files by looking them up in the editor’s file tree. I get that some people have a visual memory. But when all you want is to jump to the file &lt;code&gt;app/models/user.rb&lt;/code&gt;, why would you look for a folder, expand it, look for the next folder, expand it, and finally look for the file &lt;code&gt;user.rb&lt;/code&gt; when you can jump directly to it with a few key strokes?&lt;/p&gt;

&lt;p&gt;This is where TextMate’s &lt;em&gt;Open Quickly…&lt;/em&gt;, bound to &lt;kbd class="macos"&gt;⌘T&lt;/kbd&gt;, really shines. If I’m not mistaken, this also works in &lt;a href="https://www.sublimetext.com/"&gt;Sublime Text&lt;/a&gt; and &lt;a href="https://atom.io/"&gt;Atom&lt;/a&gt;. Type &lt;code&gt;user&lt;/code&gt; and hit return and you’re in that file. If there are multiple matching files, type a few characters more or select the correct one in the list.&lt;/p&gt;

&lt;p&gt;The search is typically fuzzy, meaning you don’t have to type all the characters in the sequence as they appear in the path name. Depending on how the fuzzy matcher works, you might be able to type less characters. E.g. if a file is called &lt;code&gt;user_profile_controller.js&lt;/code&gt;, the initial character of each word, i.e. &lt;code&gt;upc&lt;/code&gt;, might be enough to get this file as the top matching result.&lt;/p&gt;

&lt;p&gt;Other fuzzy matchers, e.g. &lt;a href="https://github.com/junegunn/fzf"&gt;fzf&lt;/a&gt;, allow you to refine your search by typing a space and more characters, effectively filtering the obtained list. For instance, let’s say you type &lt;code&gt;user&lt;/code&gt; and the following list appears:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;code&gt;tests/user_test.rb&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code&gt;lib/user.rb&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If you append another word such that your search now says &lt;code&gt;user lib&lt;/code&gt;, the list will be narrowed down to just &lt;code&gt;lib/user.rb&lt;/code&gt;. The great thing about this is that it doesn’t have to be in the order that the words appear in the path (notice how &lt;code&gt;lib&lt;/code&gt; comes before &lt;code&gt;user&lt;/code&gt; in the path).&lt;/p&gt;

&lt;p&gt;Jumping to a file is just the beginning. Once this is your default way of moving around, you might want to start looking at jumping directly to symbols (aka tags), e.g. classes and functions.&lt;/p&gt;

&lt;h3 id="line-wise-editing"&gt;Line-wise Editing&lt;/h3&gt;

&lt;p&gt;Another concept that I learned to appreciate in TextMate—and is omnipresent in Vim—is line-wise operations. I’d claim that most developers don’t know the definition of a line.&lt;/p&gt;

&lt;p&gt;A line is everything from the left edge of the text area (not where the non-whitespace starts) all the way to the end of the text &lt;em&gt;including the newline&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;When I observe people moving around lines of code, this lack of understanding results in plenty of fiddling with whitespace, like dramatized in this video:&lt;/p&gt;

&lt;video src="line-wise-not.mp4" width="520" height="259" controls=""&gt;&lt;/video&gt;

&lt;p&gt;Granted, this video shows a simple text editor. Most editors anicipate what you’re trying to accomplish by indenting your code and more. Still, from my experience there’s often some manual clean up needed.&lt;/p&gt;

&lt;p&gt;On the other hand, if you use line-wise selection by triple clicking, you can cut and paste that line much easier:&lt;/p&gt;

&lt;video src="line-wise.mp4" width="520" height="259" controls=""&gt;&lt;/video&gt;

&lt;p&gt;Some editors also allow you to select an entire line with a keyboard shortcut so you don’t have to reach for the mouse. Also, there’s often a shortcut to move one or multiple lines around without cut and paste.&lt;/p&gt;

&lt;h2 id="terminal"&gt;Terminal&lt;/h2&gt;

&lt;p&gt;For some, the terminal is their primary tool to get work done—like me. Others avoid it and prefer a GUI whenever possible. Even then, probably you still have to use it occasionally for certain tasks.&lt;/p&gt;

&lt;p&gt;Thus, why not invest a bit in this tool to make your life easier?&lt;/p&gt;

&lt;p&gt;Note that in this section I’ll be using the Emacs-style notation for keyboard shortcuts. To quote from Bash’s manual:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Control keys are denoted by &lt;kbd&gt;C-key&lt;/kbd&gt;, e.g., &lt;kbd&gt;C-n&lt;/kbd&gt; means &lt;kbd&gt;Control&lt;/kbd&gt;-&lt;kbd&gt;N&lt;/kbd&gt;. Similarly, meta keys are denoted by &lt;kbd&gt;M-key&lt;/kbd&gt;, so &lt;kbd&gt;M-x&lt;/kbd&gt; means &lt;kbd&gt;Meta&lt;/kbd&gt;-&lt;kbd&gt;X&lt;/kbd&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;When I see others use the terminal, most move around the command line character by character. It certainly isn’t obvious how to move the cursor around other than using just the left and right keys. Often the person at least knows &lt;kbd&gt;C-a&lt;/kbd&gt; and &lt;kbd&gt;C-e&lt;/kbd&gt; to jump to the beginning and end of the line, so they jump to the closest end and then move from there to the place where they want to edit the line.&lt;/p&gt;

&lt;p&gt;There are plenty of keyboard shortcuts that will make this so much easier. In fact, these shortcuts work pretty much on every command line, i.e. in your shell as well as in &lt;acronym title="read–eval–print loop"&gt;REPL&lt;/acronym&gt;s.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://en.wikipedia.org/wiki/GNU_Readline"&gt;GNU Readline&lt;/a&gt; is what powers these interactive command lines. Because of that, you only need to learn the basic commands once in order to use them in (almost) all shells.&lt;/p&gt;

&lt;p&gt;Here’s a short list of the most important ones (you’ll notice that they’re very similar to the shortcuts I’ve shown in &lt;a href="#cursor-movement-and-text-selection"&gt;Cursor Movement and Text Selection&lt;/a&gt;):&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;kbd&gt;C-a&lt;/kbd&gt;: move to start of line&lt;/li&gt;
  &lt;li&gt;&lt;kbd&gt;C-e&lt;/kbd&gt;: move to end of line&lt;/li&gt;
  &lt;li&gt;&lt;kbd&gt;C-b&lt;/kbd&gt;: move one character to the left (same as left arrow, but without leaving the home row)&lt;/li&gt;
  &lt;li&gt;&lt;kbd&gt;C-f&lt;/kbd&gt;: move one character to the right (same as right arrow)&lt;/li&gt;
  &lt;li&gt;&lt;kbd&gt;M-b&lt;/kbd&gt;: move one word to the left&lt;/li&gt;
  &lt;li&gt;&lt;kbd&gt;M-f&lt;/kbd&gt;: move one word to the right&lt;/li&gt;
  &lt;li&gt;&lt;kbd&gt;M-DEL&lt;/kbd&gt;: delete word to the left&lt;/li&gt;
  &lt;li&gt;&lt;kbd&gt;M-d&lt;/kbd&gt;: delete word to the right&lt;/li&gt;
  &lt;li&gt;&lt;kbd&gt;C-k&lt;/kbd&gt;: delete to the end of the line&lt;/li&gt;
  &lt;li&gt;&lt;kbd&gt;C-u&lt;/kbd&gt;: delete to the beginning of the line&lt;/li&gt;
  &lt;li&gt;&lt;kbd&gt;M-.&lt;/kbd&gt;: retrieve the last argument of the last run command&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In order to leverage the shortcuts that use the &lt;kbd&gt;Meta&lt;/kbd&gt; key, such as &lt;kbd&gt;M-b&lt;/kbd&gt;, you probably need to configure your terminal emulator to use the &lt;kbd&gt;Alt&lt;/kbd&gt; key as &lt;kbd&gt;Meta&lt;/kbd&gt;. In macOS’s Terminal app that setting is located here:&lt;/p&gt;

&lt;p&gt;&lt;img src="terminal.png" width="764" height="687" /&gt;&lt;/p&gt;

&lt;p&gt;If you happen to be an &lt;a href="https://iterm2.com/"&gt;iTerm&lt;/a&gt; user, it offers the option to map the left or right &lt;kbd&gt;Alt&lt;/kbd&gt; key. This has the benefit that you can still use the other for typing special characters. Make sure to choose &lt;em&gt;Esc+&lt;/em&gt; rather than &lt;em&gt;Meta&lt;/em&gt;:&lt;/p&gt;

&lt;p&gt;&lt;img src="iterm.png" width="1112" height="676" /&gt;&lt;/p&gt;

&lt;p&gt;I encourage you to explore these shortcuts. There’s many more that also interact with Readline’s own clipboard, the so-called kill-ring, allowing you to move arguments around without having to select and copy them first. Other shortcuts for instance allow you to change the casing of a word.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://en.wikipedia.org/wiki/GNU_Readline"&gt;Wikipedia page&lt;/a&gt; on GNU Readline has an extensive list of shortcuts. I also recommend this &lt;a href="https://readline.kablamo.org/emacs.html"&gt;cheat sheet&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id="touch-typing"&gt;Touch-typing&lt;/h2&gt;

&lt;p&gt;I believe that touch-typing is a skill absolutely worth learning if a computer is your main work tool. Hunt-and-peck might get the job done and you might even be fast at it. Heck, you might even be able to do it without looking down at your keyboard. Though from my experience while observing other developers that don’t touch-type, the error rate is quite high, especially when not looking at your keyboard.&lt;/p&gt;

&lt;p&gt;I had taken a touch-typing class in high school, but it didn’t stick. There was a competition among mostly male students to finish the exercises as quickly as possible. Of course we’d all hunt-and-peck to win.&lt;/p&gt;

&lt;p&gt;When I started my first day job as a developer, I realized that I needed to take typing seriously and force myself to learn to touch-type, even if that meant being slower initially.&lt;/p&gt;

&lt;p&gt;I used a free app to learn the basics. From there, I simply forced myself not to look. If I didn’t remember where a key was, I could look down. Yes, I was slow as heck in the beginning, but it totally paid out. My wife did the same a few years ago approaching her thirties, so I’m sure it’s never too late.&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;One might argue that at the end of the day you might not necessarily be faster at accomplishing your work by optimizing your workflow. Depending on the nature of your work, solving a problem in your head might be the lion’s share of your day, while its execution with your tools constitutes a fraction. By optimizing the execution, though, I’m confident that you can reduce the cognitive load of it, allowing you to keep focused on the underlying problem or idea, thus reducing the chance of distractions. That in itself is already worth it.&lt;/p&gt;

&lt;p&gt;Therefore, I encourage you to stay curious about your workflow and tools. Try to notice patterns and then ask yourself: &lt;em&gt;is there a better way?&lt;/em&gt; Google for what you’re trying to accomplish.&lt;/p&gt;

&lt;p&gt;Further, invest in your tools. Occasionally read their docs and browse their menus and settings. That way I’ve come across features I didn’t know existed. Having them in the back of your head will cause you to go: &lt;em&gt;wait a second, wasn’t there this feature that would accomplish what I’m doing, but much quicker?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;And for those that say “I can’t memorize shortcuts or commands”, write them down on a piece of paper and leave them somewhere visible close to your screen. The act of writing them down might already cause you to memorize them. If not, next time you need that one shortcut, glance down. After a few times you’ll know it by heart.&lt;/p&gt;

&lt;p&gt;I like to observe how others work and learn from their unique setups and workflows. If you have a tool or tip you’d like to share, I’d love to hear from you.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Loading Additional Ruby Gems in Development</title>
    <summary>Using your favorite gems without adding them to your project's Gemfile</summary>
    <link rel="alternate" type="text/html" href="https://phili.pe/posts/loading-additional-ruby-gems-in-development/"/>
    <id>https://phili.pe/posts/loading-additional-ruby-gems-in-development/</id>
    <published>2019-10-20T00:00:00Z</published>
    <updated>2019-10-20T12:02:24Z</updated>
    <author>
      <name>Philipe Fatio</name>
    </author>
    <content type="html">&lt;p&gt;Have you ever found yourself temporarily adding a gem to your project’s Gemfile to leverage it during development? Maybe your project even has gems that some team members find indispensable during development, but mean nothing to others. Luckily, there’s a way to have your favorite gems available without permanently or temporarily adding them to the project’s Gemfile.&lt;/p&gt;

&lt;p&gt;Recently at my company we were spring cleaning our app’s Gemfile. Over the years people have added gems to it that they heavily rely on during development, myself included.&lt;/p&gt;

&lt;p&gt;I always use the &lt;a href="https://github.com/thekompanee/fuubar"&gt;Fuubar&lt;/a&gt; formatter for RSpec and greatly prefer it over the default formatter. Sporadically I might need to get a flame graph for a performance critical part of the app, so I temporarily add the &lt;a href="https://github.com/SamSaffron/flamegraph"&gt;Flamegraph&lt;/a&gt; gem. Other times I can’t wrap my head around Rails’ implicit i18n key resolution, so I quickly add my &lt;a href="https://github.com/fphilipe/i18n-debug"&gt;i18n-debug&lt;/a&gt; gem.&lt;/p&gt;

&lt;p&gt;While doing this spring cleaning someone pointed out that there’s a way to use a different Gemfile locally that allows you to add additional gems. This sounded like the correct approach that would make everyone happy.&lt;/p&gt;

&lt;p&gt;As it wasn’t straightforward to set this up and getting it to work correctly, especially in the context of a Rails app using &lt;a href="https://github.com/rails/spring"&gt;Spring&lt;/a&gt; and &lt;a href="https://github.com/puma/puma-dev"&gt;Puma-dev&lt;/a&gt; or &lt;a href="http://pow.cx"&gt;Pow&lt;/a&gt;, I wanted to document the necessary steps. Hopefully this comes in handy for someone else.&lt;/p&gt;

&lt;ul id="markdown-toc"&gt;
  &lt;li&gt;&lt;a id="markdown-toc-setting-up-a-private-gemfile" href="#setting-up-a-private-gemfile"&gt;Setting up a Private Gemfile&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a id="markdown-toc-executing-commands-using-your-private-gemfile" href="#executing-commands-using-your-private-gemfile"&gt;Executing Commands Using Your Private Gemfile&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a id="markdown-toc-configuring-spring" href="#configuring-spring"&gt;Configuring Spring&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a id="markdown-toc-configuring-puma-dev-or-pow" href="#configuring-puma-dev-or-pow"&gt;Configuring Puma-dev or Pow&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id="setting-up-a-private-gemfile"&gt;Setting up a Private Gemfile&lt;/h2&gt;

&lt;p&gt;In the root directory of a typical Ruby project you’ll have a &lt;code&gt;Gemfile&lt;/code&gt; and a &lt;code&gt;Gemfile.lock&lt;/code&gt;. The first step is creating a second Gemfile with a name of your choice, e.g. &lt;code&gt;Gemfile.private&lt;/code&gt;. I first went with &lt;code&gt;Gemfile.local&lt;/code&gt; as that’s what you find here and there on the internet, but I’ve found that &lt;code&gt;Gemfile.local&lt;/code&gt;, &lt;code&gt;Gemfile.lock&lt;/code&gt;, and &lt;code&gt;Gemfile.local.lock&lt;/code&gt; are all too similar and ambiguous when using tab completion.&lt;/p&gt;

&lt;p&gt;This file will evaluate the project’s &lt;code&gt;Gemfile&lt;/code&gt; and list additional gems of your choice. Here’s how mine looks like:&lt;/p&gt;

&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;eval_gemfile&lt;/span&gt; &lt;span class="s1"&gt;'Gemfile'&lt;/span&gt;

&lt;span class="n"&gt;gem&lt;/span&gt; &lt;span class="s1"&gt;'fuubar'&lt;/span&gt;

&lt;span class="n"&gt;gem&lt;/span&gt; &lt;span class="s1"&gt;'stackprof'&lt;/span&gt;
&lt;span class="n"&gt;gem&lt;/span&gt; &lt;span class="s1"&gt;'flamegraph'&lt;/span&gt;

&lt;span class="n"&gt;gem&lt;/span&gt; &lt;span class="s1"&gt;'i18n-debug'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We now need to run &lt;code&gt;bundle install&lt;/code&gt; while instructing Bundler to use this Gemfile instead.&lt;/p&gt;

&lt;p&gt;Before doing so, it makes sense to use the &lt;code&gt;Gemfile.lock&lt;/code&gt; as the starting point for version resolution. This ensures that we’ll get the same versions of the gems defined in &lt;code&gt;Gemfile&lt;/code&gt;, especially if you’re using &lt;a href="https://guides.rubygems.org/patterns/#pessimistic-version-constraint"&gt;pessimistic version constraints&lt;/a&gt;.&lt;/p&gt;

&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ cp Gemfile.lock Gemfile.private.lock
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now we can &lt;code&gt;bundle install&lt;/code&gt; using &lt;code&gt;Gemfile.private&lt;/code&gt;:&lt;/p&gt;

&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ BUNDLE_GEMFILE=Gemfile.private bundle install
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Because you’ll be using &lt;code&gt;Gemfile.private&lt;/code&gt; during development, you’ll have to remember to do changes, which should be checked in, directly on the &lt;code&gt;Gemfile&lt;/code&gt; and &lt;code&gt;Gemfile.lock&lt;/code&gt;, e.g. when updating or adding a gem.&lt;/p&gt;

&lt;p&gt;On the other hand, whenever &lt;code&gt;Gemfile.lock&lt;/code&gt; was changed upstream, you’ll have to redo the copy and &lt;code&gt;bundle install&lt;/code&gt; step for your private Gemfile in order for your &lt;code&gt;Gemfile.private.lock&lt;/code&gt; to include those upstream changes.&lt;/p&gt;

&lt;p&gt;I have written a &lt;a href="https://github.com/fphilipe/bundler-private_install"&gt;Bundler plugin&lt;/a&gt; that takes care of this step whenever running &lt;code&gt;bundle install&lt;/code&gt;. To install the plugin globally, run the following in a directory that doesn’t have a Gemfile:&lt;/p&gt;

&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ bundle plugin install bundler-private_install
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id="executing-commands-using-your-private-gemfile"&gt;Executing Commands Using Your Private Gemfile&lt;/h2&gt;

&lt;p&gt;When running a command through Bundler, you’ll need to set the &lt;code&gt;BUNDLE_GEMFILE&lt;/code&gt; environment variable for Bundler to load the gems specified in your private Gemfile.&lt;/p&gt;

&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ BUNDLE_GEMFILE=Gemfile.private bundle exec foobar
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;You can also export &lt;code&gt;BUNDLE_GEMFILE&lt;/code&gt; in your shell so you don’t have to repeat it for every command:&lt;/p&gt;

&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ export BUNDLE_GEMFILE=Gemfile.private
$ bundle exec foobar
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;If you’re using &lt;a href="https://bundler.io/man/bundle-binstubs.1.html"&gt;Bundler binstubs&lt;/a&gt;, have a look at a binstub. You’ll notice at the top of a binstub that it supports &lt;code&gt;BUNDLE_GEMFILE&lt;/code&gt;:&lt;/p&gt;

&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="no"&gt;ENV&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"BUNDLE_GEMFILE"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;||=&lt;/span&gt; &lt;span class="no"&gt;File&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;expand_path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"../../Gemfile"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="no"&gt;Pathname&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kp"&gt;__FILE__&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;realpath&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This means that your binstubs will pick up your private Gemfile:&lt;/p&gt;

&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ BUNDLE_GEMFILE=Gemfile.private bin/rake
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Rails binstubs are slightly different as they don’t load Bundler directly, but instead load &lt;code&gt;config/boot.rb&lt;/code&gt;, which supports &lt;code&gt;BUNDLE_GEMFILE&lt;/code&gt; as well. At the top of &lt;code&gt;config/boot.rb&lt;/code&gt; you’ll see a similar snippet:&lt;/p&gt;

&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="no"&gt;ENV&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'BUNDLE_GEMFILE'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;||=&lt;/span&gt; &lt;span class="no"&gt;File&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;expand_path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'../Gemfile'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;__dir__&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;A few lines later, after having set &lt;code&gt;BUNDLE_GEMFILE&lt;/code&gt;, it loads the Bundler setup.&lt;/p&gt;

&lt;p&gt;If you’re working with &lt;a href="https://github.com/rails/spring"&gt;Spring&lt;/a&gt; and a server such as &lt;a href="https://github.com/puma/puma-dev"&gt;Puma-dev&lt;/a&gt; or &lt;a href="http://pow.cx"&gt;Pow&lt;/a&gt;, you’ll have to go through a few extra hoops described below.&lt;/p&gt;

&lt;h2 id="configuring-spring"&gt;Configuring Spring&lt;/h2&gt;

&lt;p&gt;When running commands that leverage a preloaded application through Spring, such as &lt;code&gt;rails console&lt;/code&gt; or &lt;code&gt;rspec&lt;/code&gt;, it will not pick up the &lt;code&gt;BUNDLE_GEMFILE&lt;/code&gt; that’s set in the shell.&lt;/p&gt;

&lt;p&gt;Luckily, Spring provides &lt;a href="https://github.com/rails/spring#configuration"&gt;configuration hooks&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Spring will read &lt;code&gt;~/.spring.rb&lt;/code&gt; and &lt;code&gt;config/spring.rb&lt;/code&gt; for custom settings. Note that &lt;code&gt;~/.spring.rb&lt;/code&gt; is loaded before bundler, but &lt;code&gt;config/spring.rb&lt;/code&gt; is loaded after bundler.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Because we need &lt;code&gt;BUNDLE_GEMFILE&lt;/code&gt; to be set before Bundler is loaded and because we want to do this config globally and not for every project where we want a private Gemfile, the &lt;code&gt;~/.spring.rb&lt;/code&gt; file is the right spot.&lt;/p&gt;

&lt;p&gt;Add the following snippet to &lt;code&gt;~/.spring.rb&lt;/code&gt; that sets &lt;code&gt;BUNDLE_GEMFILE&lt;/code&gt; if there is one (note that this file gets evaluated in your project’s root):&lt;/p&gt;

&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="no"&gt;ENV&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'BUNDLE_GEMFILE'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Gemfile.private'&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="no"&gt;File&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;exist?&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Gemfile.private'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now, whenever you’re working on an app that has a &lt;code&gt;Gemfile.private&lt;/code&gt;, you’ll have your additional gems available inside Spring-powered commands.&lt;/p&gt;

&lt;h2 id="configuring-puma-dev-or-pow"&gt;Configuring Puma-dev or Pow&lt;/h2&gt;

&lt;p&gt;Similarly as for Spring, we need to configure Puma-dev or Pow to set &lt;code&gt;BUNDLE_GEMFILE&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Puma-dev also features a set of config files according to the &lt;a href="https://github.com/puma/puma-dev#advanced-configuration"&gt;advanced configuration&lt;/a&gt; section of the docs:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Puma-dev supports loading environment variables before puma starts. It checks for the following files in this order:&lt;/p&gt;

  &lt;ul&gt;
    &lt;li&gt;&lt;code&gt;~/.powconfig&lt;/code&gt;&lt;/li&gt;
    &lt;li&gt;&lt;code&gt;.env&lt;/code&gt;&lt;/li&gt;
    &lt;li&gt;&lt;code&gt;.powrc&lt;/code&gt;&lt;/li&gt;
    &lt;li&gt;&lt;code&gt;.powenv&lt;/code&gt;&lt;/li&gt;
  &lt;/ul&gt;
&lt;/blockquote&gt;

&lt;p&gt;The &lt;code&gt;~/.powconfig&lt;/code&gt; file is exactly what we need. Puma-dev, dubbed “the emotional successor to pow”, simply uses the same file as Pow. In case you’re still using Pow, the relevant section of the manual is &lt;a href="http://pow.cx/manual.html#section_3"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Analogous to &lt;code&gt;~/.spring.rb&lt;/code&gt;, we set &lt;code&gt;BUNDLE_GEMFILE&lt;/code&gt; in &lt;code&gt;~/.powconfig&lt;/code&gt;, which is a shell script:&lt;/p&gt;

&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;[&lt;/span&gt; -f Gemfile.private &lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;BUNDLE_GEMFILE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;Gemfile.private
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;As for Spring, this file is evaluated in the root of the app being booted.&lt;/p&gt;

&lt;p&gt;Remember to restart the app with &lt;code&gt;touch tmp/restart.txt&lt;/code&gt; if it was running. After that, whenever Puma-dev boots an app, it’ll first set &lt;code&gt;BUNDLE_GEMFILE&lt;/code&gt; if a private Gemfile exists.&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;I hope that this guide helped you in setting up your private Gemfile.&lt;/p&gt;

&lt;p&gt;As a final tip, if you’re working on multiple projects and find yourself adding the same set of gems, you could have a global private Gemfile, e.g. at &lt;code&gt;~/Gemfile.private&lt;/code&gt; and simply link to that file in your project:&lt;/p&gt;

&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ ln -s ~/Gemfile.private
&lt;/code&gt;&lt;/pre&gt;
</content>
  </entry>
</feed>
