Jekyll2017-01-18T21:38:30-06:00http://hypepat.com//hypepatPat GaffneyCreating Pull Requests from Local Clones2017-01-18T00:00:00-06:002017-01-18T00:00:00-06:00http://hypepat.com/2017/creating-pull-requests-from-local-clones<p>Here is a workflow I often find myself in: </p>
<ul>
<li>I want to test out a potential solution some open source project offers.
<ul>
<li><em>Alternatively</em>, I am about to begin work on a legacy project at work and want to check out the code before I get commit access.</li>
</ul></li>
<li>I clone the repository to play with it.</li>
<li>I notice a bug or a simple feature that’s missing.</li>
<li>I make a new branch and fix/add the bug/feature.</li>
<li>I push the new branch to a new repository on <em>my</em> Github.</li>
<li>Github has no idea I began this process by cloning — therefore it’s impossible to create a pull request.</li>
<li>WTFFFFFF 😡❗️😤‼️😩⁉️😫❓😖</li>
</ul>
<p>The simple solution: <strong>just fork it</strong>. If I had made a fork in the beginning instead of cloning someone else’s repository, my new branch would have been evidence enough for Github to give me the opportunity to make a pull request.</p>
<p>There is a way to get out of this mess, but you still have to create a fork. Lets jump back to when I checked-out a new branch and committed some changes.</p>
<blockquote>
<ul>
<li>I make a new branch and fix/add the bug/feature.</li>
</ul>
</blockquote>
<p>At this point, we have to tell Github that we actually <em>forked</em> this repository:</p>
<ul>
<li>Go to the original repository on Github and fork it.</li>
<li><p>Rename the remote (base repository) in your local clone from <code>origin</code> to <code>upstream</code>.</p>
<div class="highlight"><pre><code class="language-text" data-lang="text"><span></span>git remote rename origin upstream
</code></pre></div></li>
<li><p>Add <strong>your fork</strong> to as a remote — the <code>origin</code> — on your local clone.</p>
<div class="highlight"><pre><code class="language-text" data-lang="text"><span></span>git remote add origin <link-to-your-forked-repo>
</code></pre></div></li>
<li><p>Push the new branch to <strong>your forked repository</strong>.</p>
<div class="highlight"><pre><code class="language-text" data-lang="text"><span></span>git push --all
</code></pre></div></li>
<li><p>Go to your forked repository on Github and switch to the new branch.</p></li>
<li><p>Create the pull request.</p></li>
<li><p>Take a deep breath. </p></li>
</ul>Pat GaffneyHere is a workflow I often find myself in:Removing a File from All past Git Commits2017-01-16T00:00:00-06:002017-01-16T00:00:00-06:00http://hypepat.com/2017/removing-a-file-from-all-past-git-commits<p>I have a tendency not to add <code>.DS_Store</code> to my <code>.gitignore</code> until I’ve already pushed to Github. Every single goddamn time it happens, I have to spend ten minutes googling for the answer.</p>
<p>Well, <a href="https://en.wikipedia.org/wiki/Here_be_dragons">here be dragons</a>:</p>
<div class="highlight"><pre><code class="language-bash" data-lang="bash"><span></span>git filter-branch --index-filter <span class="s1">'git rm --cached --ignore-unmatch .DS_Store'</span> HEAD
</code></pre></div>
<ul>
<li>The <code>filter-branch</code> <a href="https://git-scm.com/docs/git-filter-branch">command</a> rewrites commit history based on the filter that you provide. </li>
<li>The <code>--index-filter</code> tells git to rewrite the index — it doesn’t check out the tree, which is <a href="https://git-scm.com/docs/git-filter-branch#git-filter-branch---index-filterltcommandgt">apparently faster</a>. </li>
<li>The filter we’re passing tells git to remove the <code>.DS_Store</code> from the staging area and delete it’s paths from the index — aka <code>--cached</code>. </li>
<li>The <code>ignore-unmatch</code> flag does exactly that, the remove command exits with a 0 status even if no matches were found.</li>
</ul>
<p>May the git lords have pity on your soul.</p>Pat GaffneyI have a tendency not to add .DS_Store to my .gitignore until I’ve already pushed to Github. Every single goddamn time it happens, I have to spend ten minutes googling for the answer.Python & Swift: Loathing Your Tools2016-09-28T00:00:00-05:002016-09-28T00:00:00-05:00http://hypepat.com/2016/python-swift-loathing-your-tools<p>Here is a fun way to waste some time: ensure that you have Python 2.7.12 <sup id="fnref1"><a href="#fn1" rel="footnote">1</a></sup> installed on your Mac via homebrew or whatever, then launch the swift REPL. You can do this now by just typing <code>swift</code>. Your welcome.</p>
<div class="highlight"><pre><code class="language-bash" data-lang="bash"><span></span>Traceback <span class="o">(</span>most recent call last<span class="o">)</span>:
File <span class="s2">"<string>"</span>, line <span class="m">1</span>, in <module>
File <span class="s2">"/Applications/Xcode.app/Contents/SharedFrameworks/LLDB.framework/Resources/Python/lldb/__init__.py"</span>, line <span class="m">98</span>, in <module>
import six
ImportError: No module named six
Traceback <span class="o">(</span>most recent call last<span class="o">)</span>:
File <span class="s2">"<string>"</span>, line <span class="m">1</span>, in <module>
NameError: name <span class="s1">'run_one_line'</span> is not defined
Traceback <span class="o">(</span>most recent call last<span class="o">)</span>:
File <span class="s2">"<string>"</span>, line <span class="m">1</span>, in <module>
NameError: name <span class="s1">'run_one_line'</span> is not defined
Traceback <span class="o">(</span>most recent call last<span class="o">)</span>:
File <span class="s2">"<string>"</span>, line <span class="m">1</span>, in <module>
NameError: name <span class="s1">'run_one_line'</span> is not defined
</code></pre></div>
<p>That nonsense will fill your terminal faster than you can even hit <code>Control-D</code>. It could almost be a game — count the number of <code>NameError</code> dialogs, the lower number wins. I call it… <code>NameError</code> golf.</p>
<p>Well what’s going on here? If you go all the way back to the top of what is now the longest terminal session in history — back to when you typed in <code>swift</code> — you will see the first <code>Traceback</code>. Ahh, it appears <a href="http://lldb.llvm.org">LLDB</a> runs some Python script when starting the Swift REPL. And somewhere in that file an attempt is made to load the <code>six</code> module.</p>
<p>What the hell is the <code>six</code> module, and why do I care?</p>
<p>The <code>six</code> module — and now I’m just going to quote from <a href="http://pythonhosted.org/six/">the package site</a> — “provides simple utilities for wrapping over differences between Python 2 and Python 3.”</p>
<p>Yes, that’s right. The culprit is a module that makes it easier to write Python 2 code. Ughhhh.</p>
<h2>Fixing This “Problem”</h2>
<p>The reason I am getting this error message — in case you already haven’t guessed — is because I have Python 2.7.12 installed. It’s from homebrew. I’m fairly sure that I got it back before 2.7.10 and it’s just been updating itself everytime I <code>brew update; brew upgrade</code>.</p>
<p>For reasons which I won’t go into now I have my homebrew Python binary ahead of my macOS default Python binary in the <code>$PATH</code>. I also don’t have the <code>six</code> module installed for that binary. Normally this isn’t a problem for me because I try my damnest to write everything in Python 3.</p>
<p>So, you can solve this problem by doing one of two things:</p>
<ol>
<li><code>brew uninstall python</code></li>
<li><code>pip install six</code></li>
</ol>
<p>I chose the first option, because it’s time to <a href="https://wiki.python.org/moin/Python2orPython3">stop living in the past</a>.</p>
<div class="footnotes">
<hr>
<ol>
<li id="fn1">
<p>As of writing this, that is the latest version of Python on the 2.7.x track. Really, all you need for this little adventure is for the <code>python</code> binary to <em>not</em> be the default shipped with macOS. <a href="#fnref1" rev="footnote">↩</a></p>
</li>
</ol>
</div>Pat GaffneyHere is a fun way to waste some time: ensure that you have Python 2.7.12 1 installed on your Mac via homebrew or whatever, then launch the swift REPL. You can do this now by just typing swift. Your welcome.
As of writing this, that is the latest version of Python on the 2.7.x track. Really, all you need for this little adventure is for the python binary to not be the default shipped with macOS. ↩Two Shells and A Prompt2016-09-24T00:00:00-05:002016-09-24T00:00:00-05:00http://hypepat.com/2016/two-shells-one-prompt<p>I recently made the switch back to <a href="http://tiswww.case.edu/php/chet/bash/bashtop.html">bash</a> after a long spell with <a href="http://zsh.sourceforge.net">zsh</a>. I’m a little conflicted, but there were three driving factors in my breakup with zsh:</p>
<ol>
<li>Zsh can be pretty slow sometimes — especially when you add <a href="http://ohmyz.sh">oh-my-zsh</a> to the mix.</li>
<li>Bash is everywhere.</li>
<li>Virtually all shell scripts are written in bash.</li>
</ol>
<p>Lets start with the first point. <a href="https://kev.inburke.com/kevin/profiling-zsh-startup-time/">A lot</a> of people <a href="http://blog.patshead.com/2011/04/improve-your-oh-my-zsh-startup-time-maybe.html">have written</a> about why they think zsh is slow. <a href="http://superuser.com/questions/236953/zsh-starts-incredibly-slowly">Most of the time</a> it’s a combination of oh-my-zsh and overweight startup files. I could use zsh without oh-my-zsh, but that seems unreasonable. If I disable oh-my-zsh, I am going to end up rebuilding a lot of its functionality — and it will probably be half-assed in comparison. <sup id="fnref1"><a href="#fn1" rel="footnote">1</a></sup> And it’s not just the startup time, I often find myself <em>waiting</em> on the completions after triggering them. Is this worth the in-buffer command highlighting?</p>
<p>Point number two: bash is literally everywhere. Bash is already on both of the servers I pay for. When I am am forced to use a computer at my college — <em>first I find a Mac</em> — bash is already there when I launch the terminal. When I have to <code>ssh</code> into the universities Linux servers to turn in projects, I am greeted with a friendly <code>bash4.2$</code> prompt. Bash is the air we breathe, it’s the dirt beneath our feet. It’s practically a given that it will be on any UNIX system you can find <em>and</em> it will be the default shell. Even Windows <a href="https://msdn.microsoft.com/en-us/commandline/wsl/about">has bash now</a>!</p>
<p>Bash is also the standard for writing shell scripts. If you reach a point where you or an application running needs to execute a series of commands, there is a 95% chance that it is a bash script. This doesn’t necessarily mean I have to break-up with zsh, there is actually a lot of interoperability between the two <sup id="fnref2"><a href="#fn2" rel="footnote">2</a></sup>. The problem is that I often find myself needing to change some part or parts of these scripts. It usually goes something like this:</p>
<ul>
<li>Open the script in TextMate.</li>
<li>Slowly search for the command that needs to be changed or updated.</li>
<li>Cower in fear at the foreign syntax.</li>
<li>Head for the hills, never looking back.</li>
</ul>
<p>This is no good. So my decision is made for me — if I am worth my weight in salt as a programmer, I need to learn bash. I need to be <em>proficient</em> with bash.</p>
<h2>bash and macOS</h2>
<p>When you launch the Terminal on <del>OS X</del> macOS, you are greeted with a bash prompt. The problem is, this software is roughly 10 years old. For reasons having to do with <a href="http://apple.stackexchange.com/questions/208312/why-does-apple-ship-bash-3-2">licensing</a>, Apple continues to ship version 3.2 with macOS. Meanwhile bash marches on — version 4.4 was released a week ago.</p>
<p>Luckily this is a solvable problem. <a href="http://brew.sh">Homebrew</a> exists, it’s awesome, and it’s easy:</p>
<div class="highlight"><pre><code class="language-bash" data-lang="bash"><span></span><span class="c1"># update all homebrew formulae</span>
brew update
brew install bash
<span class="c1"># change the the default shell to bash</span>
sudo chsh -s /usr/local/bash
</code></pre></div>
<p>Alright, now we have bash 4.4. But we have a long way to go before this is a replacement for zsh. For starters, the default prompt needs some surgery.</p>
<h2>Bash: A Graphic Novel</h2>
<p>When I decided to venture out into these uncharted waters, the first thing I did was search for a reference manual for bash. What do you know, one of those exists and it’s written by the current and long time maintainer <a href="http://tiswww.case.edu/php/chet/">Chet Ramey</a>. You can find it on a <a href="http://tiswww.case.edu/php/chet/bash/bashref.html">single webpage</a>, a <a href="https://www.gnu.org/software/bash/manual/bash.pdf">single PDF</a>, or a <a href="https://www.amazon.com/Bash-Reference-Manual-Chet-Ramey/dp/988838127X/ref=sr_1_1?s=books&ie=UTF8&qid=1474610205&sr=1-1">series of bounded dead tress</a> <sup id="fnref3"><a href="#fn3" rel="footnote">3</a></sup>. I opted for the dead trees, because I am a heartless bastard who loves highlighting things and reaching for books when I want answers.</p>
<p>Over a string of weekends I read this reference manual. This shouldn’t come as a surprise to anyone, but it is <strong>not</strong> a particularly compelling read. It’s called <em>Bash 4.3: Reference Manual</em> after all, not <em>Bash 4.3: A Graphic Novel</em>. Nonetheless it was enlightening. Chapter 6 of this manual deals with features specific to bash, and this is where I’ll begin.</p>
<h2>A Brief Tour Through the Bash Startup Files</h2>
<p>Bash can be <em>invoked</em> in many different ways, but all you really need to know is there are two different invocations:</p>
<ol>
<li>As an <strong>interactive shell</strong>.</li>
<li>As an <strong>non-interactive shell</strong>.</li>
</ol>
<p>Because I set bash to be my default shell, it is <em>invoked</em> when I launch the terminal. This effectively makes it an interactive shell. Alternatively, it could be invoked as a non-interactive shell. The difference appears to be mostly semantics in our GUI-based world, but depending on how bash is invoked will determine which startup files are executed. Ahh, startup files. Those are just shell scripts that are executed at the time bash is invoked. They usually tell bash to enable or disable certain features, but they can execute any arbitrary command.</p>
<p>Here is a brief tour through the bash startup file landscape:</p>
<ul>
<li>If invoked as an <strong>interactive login shell</strong>, it reads and executes commands from <code>/etc/profile</code> if it exists, then executes commands from the first file in the following list that exists and is readable:
<ol>
<li><code>~/.bash_profile</code></li>
<li><code>~/.bash_login</code></li>
<li><code>~/.profile</code></li>
</ol></li>
<li>If invoked as an <strong>interactive non-login shell</strong> (as a subshell), it reads and executes commands from <code>~/.bashrc</code>.</li>
<li>If invoked <strong>non-interactively</strong> (to run a shell script), it looks for the <code>BASH_ENV</code> environment variable, and if found it’s value is expanded and used as the name of a file to read and execute.</li>
<li>If invoked <strong>with <code>sh</code></strong>, it reads and executes commands from <code>/etc/profile</code> if it exists, then attempts to read and execute commands from <code>~/.profile</code>.</li>
<li>If invoked <strong>in POSIX mode</strong> (with the <code>--posix</code> option), it looks for the <code>ENV</code> environment variable, and if found it’s value is expanded and used as the name of a file to read and execute.</li>
<li>If invoked <strong>by a remote shell daemon</strong> (<code>sshd</code>), it attempts to read and execute commands from <code>~/.bashrc</code>.</li>
<li>If invoked with <strong>the <em>effective</em> user group id not equal to the <em>real</em> user group id</strong>, no startup files are read.</li>
</ul>
<p>This is where I would normally run for the hills.</p>
<p>Unfortunately, all these different ways of invoking bash creates uncertainty. What I want is a surefire solution to this problem — I want one file that I can guarantee will be executed every single goddamn time bash is invoked.</p>
<p>I should note that <code>/etc/profile</code> is probably not a great place to put any startup commands. If you don’t have <code>sudo</code> access, then you probably can’t edit it anyway. This file is system-wide, so it will effect anyone with an account on your machine. On my MacBook, this file only has two commands. It first executes the <code>path_helper</code> binary, then makes a call to <code>/etc/bashrc</code>, if it exists. Once again, because these files are system wide, they don’t pose a good solution to my problem.</p>
<p>My solution is to create three different files. The first two, <code>~/.bash_profile</code> and <code>~/.profile</code>, contain exactly one logical expression:</p>
<div class="highlight"><pre><code class="language-bash" data-lang="bash"><span></span><span class="c1"># if .bashrc exists, load it</span>
<span class="k">if</span> <span class="o">[</span> -f ~/.bashrc <span class="o">]</span><span class="p">;</span> <span class="k">then</span>
. ~/.bashrc<span class="p">;</span>
<span class="k">fi</span>
</code></pre></div>
<p>That’s right, I’m passing the buck. I am going to put all of the commands I want executed at startup in one file: <code>~/.bashrc</code>. I choose <code>~/.bashrc</code> because if we launch an <em>interactive non-login shell</em>, it is our only option. This takes care of four out of six of the above situations (interactive login, interactive non-login, with <code>sh</code>, by remote daemon). Thats 66%, not to shabby.</p>
<p>I am not going to concern myself with bash launching itself in <em>POSIX mode</em>, as this is something I would half to do manually, and I can just pretend it doesn’t exist. Ignorance is bliss.</p>
<p>That leaves one final scenario: bash launching <em>non-interactively</em>. I am going to punt on this scenario too — I figure I don’t need to worry about how the shell is set up in an environment where I don’t interact with it.</p>
<h2>Settings Galore</h2>
<p>Before I go all ANSI-Color-Codes on the ridiculous default prompt, lets modify some of the shells behavior. Chapter 4 of the <em>Reference Manual</em> deals with the shell commands built into bash. Two of these commands — <code>set</code> and <code>shopt</code> — change the values of shell options, thus enabling and disabling specific features.</p>
<h3>The <code>set</code> Builtin</h3>
<p>In true UNIX fashion, you can use <code>set</code> in two different ways:</p>
<ol>
<li>The <em>readable</em> way: Use <code>set -o <option-name></code> to toggle settings on or off.</li>
<li>The <em>unreadable</em> way: Use <code>set -x</code> to turn settings on, <code>set +x</code> to turn settings off.
<ul>
<li>Where <code>x</code> is a single ASCII character that corresponds to a specific <code>option-name</code>.</li>
</ul></li>
</ol>
<p>I’m going to use the first option for this, because I’m not an animal.</p>
<p>Bash comes with about half of the <code>set</code> options turned on by default, and they’re fairly sensible choices. There are two additional settings I have decided to toggle. The first, <code>ignoreeof</code>, prevents an interactive shell from exiting upon reading <code>EOF</code>. This is infinitely useful if you have ever written very buggy C code <sup id="fnref4"><a href="#fn4" rel="footnote">4</a></sup> — you end up pounding on Control-D until your keyboard breaks. The second, <code>notify</code>, prints the status of completed background jobs immediately, instead of waiting for the next prompt.</p>
<p>Finally, we actually have something in our <code>.bashrc</code>:</p>
<div class="highlight"><pre><code class="language-bash" data-lang="bash"><span></span><span class="c1"># Do not exit an interactive shell upon reading EOF.</span>
<span class="nb">set</span> -o ignoreeof<span class="p">;</span>
<span class="c1"># Report the status of terminated background jobs immediately, </span>
<span class="c1"># rather than before printing the next primary prompt.</span>
<span class="nb">set</span> -o notify<span class="p">;</span>
</code></pre></div>
<h3>The <code>shopt</code> Builtin</h3>
<p>I like to pronounce <code>shopt</code> like I assume someone from Alabama would pronounce the past-tense of “shopping.” This is the real meat and potatoes. Almost all of the options available to <code>shopt</code> are turned off by default, which makes it a goldmine. Basic usage is <code>shopt [-su] <optname></code>, where <code>s</code> sets the option and <code>u</code> unsets the option.</p>
<p>Because there are so many of theses, I am just going to list the ones I toggled on, as they appear in my <code>.bashrc</code> file. But, at minimum, everyone should really turn on the ones that correct your typos. I have also omitted the settings that are on by default.</p>
<div class="highlight"><pre><code class="language-bash" data-lang="bash"><span></span><span class="c1"># Executed a directory name as if it were an argument to cd.</span>
<span class="nb">shopt</span> -s autocd
<span class="c1"># Correct spelling errors in directory names given to cd.</span>
<span class="nb">shopt</span> -s cdspell
<span class="c1"># Check the hash table for a command name before searching $PATH.</span>
<span class="nb">shopt</span> -s checkhash
<span class="c1"># Update the window size variables after each command.</span>
<span class="nb">shopt</span> -s checkwinsize
<span class="c1"># Save all lines of a multi-line command in the same history entry.</span>
<span class="nb">shopt</span> -s cmdhist
<span class="c1"># Correct spelling errors on directory names during word completion.</span>
<span class="nb">shopt</span> -s dirspell
<span class="c1"># Enable extended pattern matching features.</span>
<span class="nb">shopt</span> -s extglob
<span class="c1"># Enable `**` pattern in filename expansion to match all files,</span>
<span class="c1"># directories and subdirectories.</span>
<span class="nb">shopt</span> -s globstar
<span class="c1"># Append the history list to $HISTFILE instead of replacing it.</span>
<span class="nb">shopt</span> -s histappend
<span class="c1"># Save multi-line commands to the history with embedded newlines</span>
<span class="c1"># instead of semicolons -- requries cmdhist to be on.</span>
<span class="nb">shopt</span> -s lithist
<span class="c1"># Do not attempt completions on an empty line.</span>
<span class="nb">shopt</span> -s no_empty_cmd_completion
<span class="c1"># Case-insensitive filename matching in filename expansion.</span>
<span class="nb">shopt</span> -s nocaseglob
<span class="c1"># Make echo builtin expand backslash-escape-sequence.</span>
<span class="nb">shopt</span> -s xpg_echo
</code></pre></div>
<h3>Useful Shell Variables</h3>
<p>Certain bash shell variables supplement the <code>shopt</code> settings, or add additional functionality. All of the variables are listed in Chapter 5 of the <em>Reference Manual</em>. If you decide to utilize any of these, ensure they are exported to override any default values.</p>
<p>The history list can be controlled via a few different variables.</p>
<div class="highlight"><pre><code class="language-bash" data-lang="bash"><span></span><span class="c1"># History file control:</span>
<span class="c1"># - ignorespace = don't save lines that begin with a space</span>
<span class="c1"># - ignoredups = don't save duplicate lines</span>
<span class="nb">export</span> <span class="nv">HISTCONTROL</span><span class="o">=</span><span class="s1">'ignorespace:ignoredups'</span>
<span class="c1"># Maximum number of lines/commands to save in the history file.</span>
<span class="nb">export</span> <span class="nv">HISTFILESIZE</span><span class="o">=</span><span class="m">150</span>
<span class="nb">export</span> <span class="nv">HISTSIZE</span><span class="o">=</span><span class="m">150</span>
</code></pre></div>
<p>Bash ships with <code>force_ignore</code> turned on by default. It uses the shell variable <code>FIGNORE</code> to list suffixes to be ignored when performing word completion. Similar functionality can be obtained for filename expansion by supplying a list of filename patterns to <code>GLOBIGNORE</code>. Both require the list to be colon-separated, much like the <code>PATH</code>.</p>
<div class="highlight"><pre><code class="language-bash" data-lang="bash"><span></span><span class="c1"># Ignore files with these suffixes when performing completion.</span>
<span class="nb">export</span> <span class="nv">FIGNORE</span><span class="o">=</span><span class="s1">'.o:.pyc'</span>
<span class="c1"># Ignore files that match these patterns when </span>
<span class="c1"># performing filename expansion.</span>
<span class="nb">export</span> <span class="nv">GLOBIGNORE</span><span class="o">=</span><span class="s1">'.DS_Store:*.o:*.pyc'</span>
</code></pre></div>
<p>Finally, lets add color to the output of the <code>ls</code> command. There is a caveat however — this is mostly OS-dependent. In other words, because <code>ls</code> is not built into bash, it is included with the operating system and therefore differs depending on who wrote the utility. I am going to cover the <code>ls</code> included on macOS <sup id="fnref5"><a href="#fn5" rel="footnote">5</a></sup>.</p>
<p>To enable colored output on <code>ls</code>, you need to do either of these two things:</p>
<ul>
<li>Supply the <code>-G</code> option to <code>ls</code> every time you use it (or set an alias).</li>
<li>Set the variable <code>CLICOLOR</code> to a non-zero integer.</li>
</ul>
<p>Since either of these options will work, I’ll just set the <code>CLICOLOR</code> variable so I can move on with my life.</p>
<p>Just telling <code>ls</code> to use colors is not enough though, you need to tell it <em>which</em> colors to use <sup id="fnref6"><a href="#fn6" rel="footnote">6</a></sup>. This is done by setting the <code>LSCOLORS</code> variable to a ridiculous string of characters, each of which corresponds to a file type, foreground color, and background color.</p>
<p>This sounds really convoluted — and it is — so my advice would be to use an <a href="http://geoff.greer.fm/lscolors/">excellent tool made by Geoff Greer</a> to generate this string for you. My settings are below.</p>
<div class="highlight"><pre><code class="language-bash" data-lang="bash"><span></span><span class="c1"># Set colors for ls command.</span>
<span class="c1"># 1. directory: ex</span>
<span class="c1"># 2. symbolic link: fx</span>
<span class="c1"># 3. socket: gx</span>
<span class="c1"># 4. pipe: bx</span>
<span class="c1"># 5. executable: cx</span>
<span class="c1"># 6. block special: aH</span>
<span class="c1"># 7. character special: aA</span>
<span class="c1"># 8. executable with setuid bit set: cA</span>
<span class="c1"># 9. executable with setgid bit set: cH</span>
<span class="c1"># 10. directory writable to others, with sticky bit: eA</span>
<span class="c1"># 11. directory writable to others, without sticky bit: eH</span>
<span class="nb">export</span> <span class="nv">CLICOLOR</span><span class="o">=</span><span class="m">1</span>
<span class="nb">export</span> <span class="nv">LSCOLOR</span><span class="o">=</span><span class="s1">'exfxgxbxcxaHaAcAcHeAeH'</span>
</code></pre></div>
<h2>A Brief Tour Through the ANSI Color Codes</h2>
<p>With oh-my-zsh I had an incredibly informative prompt, and I’m not ready to live in a world where I stare at <code>bash4.4$</code> all day. But before we start adding random special characters to our prompt string, it’s useful to understand how the shell displays colors.</p>
<p>Virtually all text terminals use <a href="https://en.wikipedia.org/wiki/ANSI_escape_code">ANSI Escape Codes</a> to control the color and formatting of strings written to the terminal. This system of using escape codes is roughly 50 years old now, so it’s not exactly intuitive. None of this is made easier by the string syntax in bash.</p>
<p>Strings in bash come in four different forms:</p>
<ul>
<li><strong>Single quotes</strong>: all characters are represented by their literal values.</li>
<li><strong>Double quotes</strong>: all characters are represented by their literal values except <code>$</code>, <code>'</code>, <code>\</code>, and <code>!</code> if history expansion is enabled.</li>
<li><strong>C-style strings</strong>: all characters are represented by their literal values except for backslash-escaped characters as specified by the ANSI C Standard.</li>
<li><strong>Locale-specific strings</strong>: all characters are translated according to the current locale.</li>
</ul>
<div class="highlight"><pre><code class="language-bash" data-lang="bash"><span></span><span class="c1"># single quoted string</span>
<span class="s1">'a string'</span>
<span class="c1"># double quoted string</span>
<span class="s2">"!ls"</span>
<span class="c1"># c-style string -- notice the `$`</span>
<span class="s1">$'\ttab then newline\n'</span>
<span class="c1"># locale-specific string -- notice the `$`</span>
<span class="s2">$"translate me"</span>
</code></pre></div>
<p>Because the color codes are escape sequences, it seems obvious we should use C-style strings. This gets tricky because the color codes are not part of the ANSI C Standard. Most <a href="https://github.com/magicmonty/bash-git-prompt/blob/master/prompt-colors.sh">popular prompts</a> get around this by using the octal code for the <a href="https://en.wikipedia.org/wiki/Escape_character#ASCII_escape_character">ASCII Escape character</a>, <code>\033</code>. While this works, you end up <em>escaping</em> the escape sequence — it makes for a huge mess of a string. Luckily, bash provides the <code>\e</code> or <code>\E</code> sequence to print an escape character.</p>
<p>Back to the color codes, they take the basic form:</p>
<div class="highlight"><pre><code class="language-bash" data-lang="bash"><span></span><span class="c1"># \e -- escape sequence that signals an escape character</span>
<span class="c1"># {parameter;} -- a parameter to describe the formatting and color</span>
<span class="s1">$'\e[{parameter;}{parameter}m'</span>
</code></pre></div>
<p>The sequence begins with <code>\e[</code>, followed by parameters. Naturally, the order of the parameters is arbitrary. The first parameter is required, but it only needs a semicolon if there is a second parameter. The second parameter is optional, but it gets a semicolon if there is an optional third parameter, and so on. The end of the sequence is marked with the letter <code>m</code>.</p>
<p>But what the hell is a parameter? Well, it’s really just an integer code. There’s <a href="https://en.wikipedia.org/wiki/ANSI_escape_code#Colors">quite a few options</a>, the most common are:</p>
<ul>
<li><code>0</code>: reset</li>
<li><code>1</code>: bold text</li>
<li><code>30</code>: black text</li>
<li><code>31</code>: red text</li>
<li><code>32</code>: green text</li>
<li><code>33</code>: yellow text</li>
<li><code>34</code>: blue text</li>
<li><code>35</code>: magenta text</li>
<li><code>36</code>: cyan text</li>
<li><code>37</code>: white text</li>
<li><code>39</code>: default text color</li>
<li><code>40</code>: black background</li>
<li><code>41</code>: red background</li>
<li><code>42</code>: green background</li>
<li><code>43</code>: yellow background</li>
<li><code>44</code>: blue background</li>
<li><code>45</code>: magenta background</li>
<li><code>46</code>: cyan background</li>
<li><code>47</code>: white background</li>
<li><code>49</code>: default background color</li>
</ul>
<p>So, if you’re still with me, to make <code>string</code> have bold red text, your bash string would be <code>$'\e[1;31mstring'</code>. This example is a little misleading, because once we set the formatting parameters to be anything other than normal, we must reset them. If the formatting is not reset, then anytime you use that string in a parameter, variable, or command expansion all of the text past the point at which the expansion took place will use that formatting. So the correct bash string would be <code>$'\e[1;31mstring\e[0m'</code></p>
<h2>Building a Better Prompt</h2>
<p>The default bash prompt is <code>bash-4.4$</code>. Actually, this is just the <em>first</em> prompt string, there are four in total. Each prompt is set by the shell variable <code>PS#</code> where <code>#</code> is 1, 2, 3, or 4. <code>PS1</code> is the prompt printed after — or before, depending how you look at it — every command is executed.</p>
<h3>Prompt Escape Sequences</h3>
<p>Bash has quite a few special characters which — when they appear in the prompt string — output generated text. The most useful are listed below:</p>
<ul>
<li><code>\d</code>: The date, as “Weekday Month Day”.</li>
<li><code>\e</code>: An escape character.</li>
<li><code>\h</code>: The hostname of the machine, up to the first <code>.</code>.</li>
<li><code>\H</code>: The hostname of the machine.</li>
<li><code>\n</code>: A newline.</li>
<li><code>\s</code>: The name of the shell.</li>
<li><code>\t</code>: The time, in 24-hour “HH:MM:SS” format.</li>
<li><code>\T</code>: The time, in 12-hour “HH:MM:SS” format.</li>
<li><code>\@</code>: The time, in 24-hour am/pm format.</li>
<li><code>\A</code>: The time, in 24-hour “HH:MM” format.</li>
<li><code>\u</code>: The username of the current user.</li>
<li><code>\v</code>: The version of bash.</li>
<li><code>\w</code>: The current working directory, with a <code>~</code> representing <code>$HOME</code>.</li>
<li><code>\w</code>: The basename of <code>$PWD</code>, with a <code>~</code> representing <code>$HOME</code>.</li>
<li><code>\#</code>: The command number of this command.</li>
</ul>
<p>For example, that default bash prompt, <code>bash-4.4$</code>, would be set as:</p>
<div class="highlight"><pre><code class="language-bash" data-lang="bash"><span></span><span class="nv">PS1</span><span class="o">=</span><span class="s1">'\s-\v$'</span>
</code></pre></div>
<h3>Making a Basic Prompt</h3>
<p>To get the ball rolling, I want a prompt that at minimum tells me:</p>
<ul>
<li>The number of commands I have executed.</li>
<li>My username.</li>
<li>The hostname.</li>
<li>The working directory.</li>
<li>The time.</li>
</ul>
<p>None of these are ridiculous requests. In fact, all of them have prompt escape sequences.</p>
<div class="highlight"><pre><code class="language-bash" data-lang="bash"><span></span><span class="nb">export</span> <span class="nv">PS1</span><span class="o">=</span><span class="s1">'\#. \u@\h in \w at \A\n$ '</span>
</code></pre></div>
<p>On my local machine, this will give me the following prompt:</p>
<div class="highlight"><pre><code class="language-text" data-lang="text"><span></span>17. patrickrgaffney@patmac in ~/Code/dotfiles at 16:44
$
</code></pre></div>
<p>Not a bad start. My only concern is that once I get deep into some nested directory the first line is going to end up wrapping. I already added a newline in order to give myself room to actually type commands. </p>
<p>Bash uses the shell variable <code>PROMPT_DIMTRIM</code> to fix this problem. If set to a positive integer, that value is used as the number of trailing directory components to retain when expanding the current working directory for the <code>\w</code> and <code>\W</code> prompt string escapes. Directories that are removed are replaced with an ellipsis.</p>
<p>I have it set to <code>3</code> in my <code>.bashrc</code>:</p>
<div class="highlight"><pre><code class="language-bash" data-lang="bash"><span></span><span class="c1"># Hide all but the 3 deepest directories for PS1.</span>
<span class="nb">export</span> <span class="nv">PROMPT_DIRTRIM</span><span class="o">=</span><span class="m">3</span>
<span class="c1"># Set the prompt.</span>
<span class="nb">export</span> <span class="nv">PS1</span><span class="o">=</span><span class="s1">'\#. \u@\h in \w at \A\n$ '</span>
</code></pre></div>
<p>This fixes my nested directory issue:</p>
<div class="highlight"><pre><code class="language-text" data-lang="text"><span></span>3. patrickrgaffney@patmac in ~/.../.git/objects/info at 17:00
$
</code></pre></div>
<h3>Adding Some Color to the Prompt</h3>
<p>We already know how the ANSI color codes work, so this should be no big deal. Truthfully, the hardest part was choosing which prompt escape sequence got which color. I also decided to split up the assignment of <code>PS1</code> into multiple assignments. Bash allows strings to be appended to each other with the <code>+=</code> operator. Also note the addition of <code>$</code> to the front of the strings in order to make them C-style strings.</p>
<div class="highlight"><pre><code class="language-bash" data-lang="bash"><span></span><span class="c1"># Begin appending information to PS1</span>
<span class="nb">export</span> <span class="nv">PS1</span><span class="o">=</span><span class="s1">''</span>
<span class="c1"># Add cyan command-number: '\#'</span>
<span class="nv">PS1</span><span class="o">+=</span><span class="s1">$'\e[1;36m\#.\e[0m'</span>
<span class="c1"># Add bold username: '\u'</span>
<span class="nv">PS1</span><span class="o">+=</span><span class="s1">$' \e[1m\u\e[0m'</span>
<span class="c1"># Add bold-blue hostname: '\h'</span>
<span class="nv">PS1</span><span class="o">+=</span><span class="s1">$'\e[1;34m@\h\e[0m in'</span>
<span class="c1"># Add bold-red working directory: '\w'</span>
<span class="nv">PS1</span><span class="o">+=</span><span class="s1">$'\e[1;31m\w\e[0m'</span>
<span class="c1"># Add bold-green time: '\A'</span>
<span class="nv">PS1</span><span class="o">+=</span><span class="s1">$'at \e[1;32m\A\e[0m'</span>
<span class="c1"># Add dollar-sign `$`</span>
<span class="nv">PS1</span><span class="o">+=</span><span class="s1">$'\n$ '</span>
<span class="c1"># Hide all but the 3 deepest directories for PS1.</span>
<span class="nb">export</span> <span class="nv">PROMPT_DIRTRIM</span><span class="o">=</span><span class="m">3</span>
</code></pre></div>
<p>Which gives me:</p>
<div class="highlight"><pre><span class="kc">25. </span><span class="gs">patrickrgaffney</span>@<span class="nf">patmac</span> in <span class="nt gs">~/Code/dotfiles</span> at <span class="s gs">17:11</span>
$</pre>
</div>
<p>So far, so good.</p>
<h3>Displaying the Git Branch</h3>
<p>I use <a href="https://git-scm.com">Git</a> for just about everything I do. It’s completely transformed the way I work on projects and keep track of schoolwork. One of git’s best features is the cheap branching. You can create a branch for anything, any time, and it’s so inexpensive that it’s invaluable.</p>
<p>Git comes with a <a href="https://github.com/git/git/blob/master/contrib/completion/git-prompt.sh">shell script</a> that you can use to add branching information to your prompt. Frankly, it has a lot more functionality than I will ever use, or really care to learn to use. And considering I’m trying to familiarize myself with the bash syntax, I should probably try and roll my own solution.</p>
<p>If you run <code>git branch --help</code>, you’ll find the <code>--no-color</code> option. It prints the the list of branches — with an asterisk next to the current branch — without using the ANSI color codes, even if they are turned on. This is probably the best way to get the data we need on the branches. Then it can be parsed to find which line has the <code>*</code> on it.</p>
<p>In order to use whatever solution I come up with in the prompt it has to be a function. Bash doesn’t <em>really</em> have return values from functions — at least not in the same way other languages do. But, if you call a bash function from command substitution inside a string, that function will <code>echo</code> into the string.</p>
<p>The bash shell variable <code>IFS</code> contains a list of characters that separate fields when the shell executes an expansion. When used with the <code>for-in</code> loop, it concatenates the loop variable into separate strings. In other words, set <code>IFS</code> to the newline character and <code>for line in $string</code> iterates over the lines in <code>$string</code>. Then all we have to do is pattern match against the line that has the asterisk, remove the asterisk, and <code>echo</code> the branch name.</p>
<div class="highlight"><pre><code class="language-bash" data-lang="bash"><span></span><span class="k">function</span> git_branch <span class="o">{</span>
<span class="nv">IFS</span><span class="o">=</span><span class="s1">$'\n'</span>
<span class="nb">local</span> <span class="nv">branches</span><span class="o">=</span><span class="k">$(</span>git branch --no-color <span class="m">2</span>> /dev/null<span class="k">)</span>
<span class="nb">local</span> <span class="nv">prefix</span><span class="o">=</span><span class="s1">'\* '</span>
<span class="nb">local</span> <span class="nv">string</span><span class="o">=</span><span class="s1">''</span>
<span class="k">for</span> branch in <span class="nv">$branches</span><span class="p">;</span> <span class="k">do</span>
<span class="k">if</span> <span class="o">[[</span> <span class="si">${</span><span class="nv">branch</span><span class="si">}</span> <span class="o">==</span> <span class="si">${</span><span class="nv">prefix</span><span class="si">}</span>* <span class="o">]]</span><span class="p">;</span> <span class="k">then</span>
<span class="nv">string</span><span class="o">+=</span><span class="s1">':['</span>
<span class="nv">string</span><span class="o">+=</span><span class="si">${</span><span class="nv">branch</span><span class="p">##</span><span class="nv">$prefix</span><span class="si">}</span>
<span class="nv">string</span><span class="o">+=</span><span class="s1">']'</span>
<span class="nb">break</span>
<span class="k">fi</span>
<span class="k">done</span>
<span class="nb">echo</span> <span class="nv">$string</span>
<span class="nb">unset</span> IFS
<span class="o">}</span>
</code></pre></div>
<p>The <code>${parameter##word}</code> expansion checks the beginning of <code>parameter</code> against the pattern <code>word</code>. If a match is found, the longest matching pattern is deleted.</p>
<p>To call this new function and have it <code>echo</code> that concatenated branch name into our prompt, we need to update the <code>PS1</code>:</p>
<div class="highlight"><pre><code class="language-bash" data-lang="bash"><span></span><span class="c1"># Begin appending information to PS1</span>
<span class="nb">export</span> <span class="nv">PS1</span><span class="o">=</span><span class="s1">''</span>
<span class="c1"># Add cyan command-number: '\#'</span>
<span class="nv">PS1</span><span class="o">+=</span><span class="s1">$'\e[1;36m\#.\e[0m '</span>
<span class="c1"># Add bold username: '\u'</span>
<span class="nv">PS1</span><span class="o">+=</span><span class="s1">$'\e[1m\u\e[0m'</span>
<span class="c1"># Add bold-blue hostname: '\h'</span>
<span class="nv">PS1</span><span class="o">+=</span><span class="s1">$'\e[1;34m@\h\e[0m in '</span>
<span class="c1"># Add red working directory: '\w'</span>
<span class="nv">PS1</span><span class="o">+=</span><span class="s1">$'\e[1;31m\w\e[0m'</span>
<span class="c1"># Add git information</span>
<span class="nv">PS1</span><span class="o">+=</span><span class="s1">'$(git_branch) '</span>
<span class="c1"># Add green time: '\A'</span>
<span class="nv">PS1</span><span class="o">+=</span><span class="s1">$'at \e[1;32m\A\e[0m'</span>
<span class="c1"># Add dollar-sign `$`</span>
<span class="nv">PS1</span><span class="o">+=</span><span class="s1">$'\n$ '</span>
</code></pre></div>
<p>This is good, and it works, but it has no color. When I was using oh-my-zsh, I had the branches name change colors based on the state of the repository:</p>
<ul>
<li><strong>Green branch</strong>: Nothing to commit, all files clean.</li>
<li><strong>Orange branch</strong>: Files are in the staging area.</li>
<li><strong>Yellow branch</strong>: Local repo is ahead of remote.</li>
<li><strong>Red branch</strong>: Files has been changed, nothing in the staging area.</li>
</ul>
<p>In order to replicate this functionality, we need a new function <code>git_dirty()</code>:</p>
<div class="highlight"><pre><code class="language-bash" data-lang="bash"><span></span><span class="k">function</span> git_dirty <span class="o">{</span>
<span class="nb">local</span> <span class="nv">status</span><span class="o">=</span><span class="k">$(</span>git status <span class="m">2</span>> /dev/null<span class="k">)</span>
<span class="nb">local</span> <span class="nv">push</span><span class="o">=</span><span class="s1">'Your branch is ahead'</span>
<span class="nb">local</span> <span class="nv">dirty</span><span class="o">=</span><span class="s1">'added to commit'</span>
<span class="nb">local</span> <span class="nv">commit</span><span class="o">=</span><span class="s1">'Changes to be committed'</span>
<span class="c1"># First check if the repo is dirty.</span>
<span class="k">if</span> <span class="o">[[</span> <span class="nv">$status</span> <span class="o">=</span>~ <span class="si">${</span><span class="nv">dirty</span><span class="si">}</span> <span class="o">]]</span><span class="p">;</span> <span class="k">then</span> <span class="nb">echo</span> <span class="s1">$'\e[1;31m'</span><span class="p">;</span>
<span class="c1"># Next check if changes have been staged.</span>
<span class="k">elif</span> <span class="o">[[</span> <span class="nv">$status</span> <span class="o">=</span>~ <span class="si">${</span><span class="nv">commit</span><span class="si">}</span> <span class="o">]]</span><span class="p">;</span> <span class="k">then</span> <span class="nb">echo</span> <span class="s1">$'\e[1;36m'</span><span class="p">;</span>
<span class="c1"># Check if its ahead of remote.</span>
<span class="k">elif</span> <span class="o">[[</span> <span class="nv">$status</span> <span class="o">=</span>~ <span class="si">${</span><span class="nv">push</span><span class="si">}</span> <span class="o">]]</span><span class="p">;</span> <span class="k">then</span> <span class="nb">echo</span> <span class="s1">$'\e[1;33m'</span><span class="p">;</span>
<span class="c1"># Default to clean.</span>
<span class="k">else</span> <span class="nb">echo</span> <span class="s1">$'\e[1;32m'</span><span class="p">;</span>
<span class="k">fi</span>
<span class="o">}</span>
</code></pre></div>
<p><code>git_dirty()</code> parses the commit message, searching for one of the three canned substrings it knows to look for. Depending on which one it finds, it outputs an ANSI color code. This function could easily be called from <code>git_branch()</code>:</p>
<div class="highlight"><pre><code class="language-bash" data-lang="bash"><span></span><span class="k">function</span> git_branch <span class="o">{</span>
<span class="nv">IFS</span><span class="o">=</span><span class="s1">$'\n'</span>
<span class="nb">local</span> <span class="nv">branches</span><span class="o">=</span><span class="k">$(</span>git branch --no-color <span class="m">2</span>> /dev/null<span class="k">)</span>
<span class="nb">local</span> <span class="nv">prefix</span><span class="o">=</span><span class="s1">'\* '</span>
<span class="nb">local</span> <span class="nv">string</span><span class="o">=</span><span class="s1">''</span>
<span class="k">for</span> branch in <span class="nv">$branches</span><span class="p">;</span> <span class="k">do</span>
<span class="k">if</span> <span class="o">[[</span> <span class="si">${</span><span class="nv">branch</span><span class="si">}</span> <span class="o">==</span> <span class="si">${</span><span class="nv">prefix</span><span class="si">}</span>* <span class="o">]]</span><span class="p">;</span> <span class="k">then</span>
<span class="nv">string</span><span class="o">+=</span><span class="s1">':['</span>
<span class="nv">string</span><span class="o">+=</span><span class="k">$(</span>git_dirty<span class="k">)</span>
<span class="nv">string</span><span class="o">+=</span><span class="si">${</span><span class="nv">branch</span><span class="p">##</span><span class="nv">$prefix</span><span class="si">}</span>
<span class="nv">string</span><span class="o">+=</span><span class="s1">$'\e[0m'</span>
<span class="nv">string</span><span class="o">+=</span><span class="s1">']'</span>
<span class="nb">break</span>
<span class="k">fi</span>
<span class="k">done</span>
<span class="nb">echo</span> <span class="nv">$string</span>
<span class="nb">unset</span> IFS
<span class="o">}</span>
</code></pre></div>
<p>This time <code>git_branch()</code> calls <code>git_dirty()</code> to get the color of the branch name. After it writes the branch name to the string, it resets the formatting and outputs the result. Because we’re calling <code>git_dirty()</code> from <code>git_branch()</code> we don’t have to update our prompt.</p>
<p>The final prompt:</p>
<div class="highlight"><pre><span class="kc">25. </span><span class="gs">patrickrgaffney</span>@<span class="nf">patmac</span> in <span class="nt gs">~/Code/dotfiles</span>:[<span class="s">master</span>] at <span class="s gs">17:11</span>
$</pre>
</div>
<p>This is pretty great. Now I have the majority of my zsh functionality back, and it’s all in a single bash startup file. The only major differences now are the in-buffer command highlighting <sup id="fnref7"><a href="#fn7" rel="footnote">7</a></sup> and the completions — bash does allow you to write your own programmable completions.</p>
<p>All of my bash startup files — along with a slew of other dotfiles I use — are in <a href="https://github.com/patrickrgaffney/dotfiles">my dotfiles repository on Github</a>.</p>
<div class="footnotes">
<hr>
<ol>
<li id="fn1">
<p>There are oh-my-zsh alternatives, namely <a href="https://github.com/sorin-ionescu/prezto">Prezto</a>. It was actually a fork of oh-my-zsh that was later rewritten to focus on performance. But if I am going to <em>really</em> buy-in on zsh, I should either hunker down and learn the configurations or stick with oh-my-zsh. <a href="#fnref1" rev="footnote">↩</a></p>
</li>
<li id="fn2">
<p>Anyone who has ever tried to use the <a href="http://fishshell.com">fish shell</a> can attest to the importance of your daily shell playing-nice with bash. This <em>is</em> a deal breaker. <a href="#fnref2" rev="footnote">↩</a></p>
</li>
<li id="fn3">
<p>Currently bash 4.4 has no dead tree version. So your stuck with reading the release notes for the latest features, like an animal. <a href="#fnref3" rev="footnote">↩</a></p>
</li>
<li id="fn4">
<p>Commonly referred to as just “C code”. <a href="#fnref4" rev="footnote">↩</a></p>
</li>
<li id="fn5">
<p>Apple uses the BSD utilities, so any BSD system should operate the same. <a href="#fnref5" rev="footnote">↩</a></p>
</li>
<li id="fn6">
<p>All of this is contingent on your terminal being able to display colors, which is the default on most terminals today. <a href="#fnref6" rev="footnote">↩</a></p>
</li>
<li id="fn7">
<p>This is pretty much impossible to do with bash. Zsh has <a href="http://zsh.sourceforge.net/Doc/Release/Zsh-Line-Editor.html#Character-Highlighting">its own library</a> for command line buffers that enables this feature. <a href="#fnref7" rev="footnote">↩</a></p>
</li>
</ol>
</div>Pat GaffneyI recently made the switch back to bash after a long spell with zsh. I’m a little conflicted, but there were three driving factors in my breakup with zsh:Learning Swift2015-11-16T20:33:00-06:002015-11-16T20:33:00-06:00http://hypepat.com/2015/learning-swift<p>I started working through Apple’s <a href="https://geo.itunes.apple.com/us/book/swift-programming-language/id881256329?mt=11&at=1000l8sh"><em>The Swift Programming Language</em></a> about a month ago, and I fell into a groove with Swift almost immediately. Writing Swift feels familiar — almost like I’m writing in some intermediate language between C and Python.</p>
<p>I have zero experience writing Objective-C, so I’ll avoid making direct comparisons. What I will say is Swift reads a hell of a whole lot better than Objective-C. Sometimes I end up using Github like StumbleUpon <sup id="fnref1"><a href="#fn1" rel="footnote">1</a></sup> and I find myself staring at a 3,000 line Objective-C file. The whole goddamn thing is <a href="http://nslog.com/2003/04/25/brackets">covered in square brackets</a>, and there are seemingly random references to <code>id</code> <a href="http://stackoverflow.com/questions/494114/objective-c-why-is-it-called-id">everywhere</a>. I’ve never been more terrified in my life.</p>
<p>Swift reads very <em>cleanly</em> — almost like pseudocode. I have spent the last few weekends with this brand new language, and I’m confident I could stumble my way through someone else’s code at this point. Comparatively, disregarding my feelings for bracketed markup, I feel lost when I read Objective-C. <sup id="fnref2"><a href="#fn2" rel="footnote">2</a></sup></p>
<p>I love the idea of getting in on the ground floor of something — potentially shaping the idioms that come out of this community in the next few years. When I started learning Python, this was the biggest struggle for me. I had rather basic experience in C and Java, and it seemed like there were all these <em>gotchas</em> to writing Python code. Somehow everyone knew the ins-and-outs of <code>for-in</code> loops, and I’m over here writing index variables. Later I realized there was a <a href="http://blog.startifact.com/posts/older/what-is-pythonic.html">pythonic</a> way of doing things. Swift doesn’t really have this yet, and so far it seems like <a href="http://www.quickmeme.com/img/53/53ae44a3552229814206def5de7a2dbc62a8a5d7e8cea1d1a62927b6d9093244.jpg">one of those good problems to have</a>.</p>
<div class="footnotes">
<hr>
<ol>
<li id="fn1">
<p>What ever happened to StumbleUpon? Days (probably weeks) of my life were wasted hitting the <strong>stumble</strong> button and staring blankly at the screen. More cat pics? Ice cubes that look like Hitler? Someone made a mashup of the Cheers theme song and Yeezus? <a href="#fnref1" rev="footnote">↩</a></p>
</li>
<li id="fn2">
<p>I have tried to force myself to get into Objective-C a few different times now, but it never took. It feels like an ancient language. I usually get an hour into some tutorial or walkthrough and next thing I’m looking up [bridges for Ruby][macruby]. I’m a student of the [University of Siracusa][copeland], and I feel like I should be afforded some memory protection. <a href="#fnref2" rev="footnote">↩</a></p>
</li>
</ol>
</div>Pat GaffneyI started working through Apple’s The Swift Programming Language about a month ago, and I fell into a groove with Swift almost immediately. Writing Swift feels familiar — almost like I’m writing in some intermediate language between C and Python.TextMate’s Markdown Headings2015-10-26T23:46:00-05:002015-10-26T23:46:00-05:00http://hypepat.com/2015/textmates-markdown-headings<p>One of the things I initially disliked about TextMate’s <a href="https://github.com/textmate/markdown.tmbundle">Markdown bundle</a> is the way it handles headings inside the editor. I don’t mind the <em>largeness</em> of the elements – these are headings, chances are they are going to be large when rendered on a website or published in a document.</p>
<p><img src="/assets/the_martian_headings.png" alt="You should really read The Martian"></p>
<p>I cannot stand that font.</p>
<p>It just doesn’t play well with the monospace font I use, <a href="https://github.com/nathco/Office-Code-Pro">Office Code Pro</a>. The headings look <em>very</em> thin, and I spend a lot of my time writing things in markdown. I can’t stare at these goddamn headings anymore.</p>
<p>Luckily, this is <a href="http://manual.macromates.com/en/preface#philosophy_of_textmate">TextMate</a>, so chances are there is a setting we can update to reflect my stubbornness. </p>
<p>Buried inside the “Themes” bundle <sup id="fnref1"><a href="#fn1" rel="footnote">1</a></sup> are a group of settings that control this, aptly named “Markup: Heading X”. Basically, each of these is a simple <a href="http://wiki.macromates.com/Reference/Settings">TextMate Settings</a> file that sets options for selected <a href="http://manual.macromates.com/en/scope_selectors#scope_selectors">scopes</a>. <sup id="fnref2"><a href="#fn2" rel="footnote">2</a></sup></p>
<p><img src="/assets/markdown_headings_settings.png" alt="TextMate's Theme Bundle"></p>
<p>In the <a href="https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/Drawers/Drawers.html">drawer</a> on the left the <em>Scope Selector</em> is set to <code>markup.heading.x</code>. This tells TextMate to only trigger this setting when inside that particular scope. The setting itself is rather simple – all it changes are the <code>fontSize</code> and <code>fontName</code> attributes. It seems the perpetrator in question goes by the name “Baskerville”.</p>
<p>Well, time for a face lift. I’m going to change this to <a href="http://brick.im/fonts/ptserif/">PT Serif</a>, because in this blogger’s opinion, it’s a superior font in literally every way.</p>
<p><img src="/assets/updated_martian_headings.png" alt="Rollin thru the 6ix with my sol"></p>
<p>Just look at those pound signs. <sup id="fnref3"><a href="#fn3" rel="footnote">3</a></sup> Now <em>that</em> is a font worthy of a heading.</p>
<div class="footnotes">
<hr>
<ol>
<li id="fn1">
<p>This is one of those default, <em>meta</em> bundles that comes preinstalled with TextMate. They typically contains items that other bundles use. For example, inside this bundle are the themes used to render the <a href="http://manual.macromates.com/en/commands#html_output">HTML output</a>. <a href="#fnref1" rev="footnote">↩</a></p>
</li>
<li id="fn2">
<p>Yes, I have written about <a href="http://hypepat.com/2015/python-in-textmate.html">TextMate settings before</a>. Thanks for asking. <a href="#fnref2" rev="footnote">↩</a></p>
</li>
<li id="fn3">
<p>Err… Hashtags, I mean. <a href="#fnref3" rev="footnote">↩</a></p>
</li>
</ol>
</div>Pat GaffneyOne of the things I initially disliked about TextMate’s Markdown bundle is the way it handles headings inside the editor. I don’t mind the largeness of the elements – these are headings, chances are they are going to be large when rendered on a website or published in a document.Pinned Tabs in Safari 92015-10-05T21:50:00-05:002015-10-05T21:50:00-05:00http://hypepat.com/2015/pinned-tabs-safari<p><a href="https://www.apple.com/safari/">Safari 9.0</a> shipped last week with the release of <a href="https://www.apple.com/osx/">El Capitan</a>. This version is largely a <a href="https://developer.apple.com/library/prerelease/mac/releasenotes/General/WhatsNewInSafari/Articles/Safari_9.html">feature release</a> – last year Safari got it’s root canal, now it’s time for a cleaning.</p>
<p>By far, the <a href="http://www.macworld.com/article/2984483/ios/hands-on-with-content-blocking-safari-extensions-in-ios-9.html">most</a> <a href="http://thenextweb.com/apple/2015/08/24/ios-9-content-blocking-will-transform-the-mobile-web-ive-tried-it/">talked</a> <a href="http://techcrunch.com/gallery/everything-you-need-to-know-about-ios-9s-new-content-blockers/">about</a> component of Safari 9 was the content blocking extensions it brought to iOS. Although this is big news, there are plenty of other features tucked away in the <a href="https://developer.apple.com/library/prerelease/mac/releasenotes/General/WhatsNewInSafari/Articles/Safari_9.html">release notes</a>. In no particular order, Safari added:</p>
<ul>
<li>a Force Touch Trackpad Events API</li>
<li>Airplay of HTML5 media to your Apple TV</li>
<li>a <code>SFSafariViewController</code> to replace the troubled <code>UIWebView</code></li>
<li>CSS Scroll Snapping</li>
<li>CSS Backdrop filters <sup id="fnref1"><a href="#fn1" rel="footnote">1</a></sup></li>
<li>a redesign of the Web Inspector
<ul>
<li>including <a href="http://www.mcelhearn.com/use-safaris-responsive-design-mode-in-el-capitan/">Responsive Design Mode</a></li>
</ul></li>
<li>ECMAScript 6 enhancements</li>
<li>support for the use of system fonts in CSS</li>
<li>support for a handful of CSS4 selectors</li>
<li>“pinned tab” support</li>
</ul>
<p>Of these, <strong>pinned tabs</strong> is the most user-facing feature, and it adds some additional markup. This is something <a href="https://support.mozilla.org/en-US/kb/pinned-tabs-keep-favorite-websites-open">Firefox</a> and <a href="https://support.google.com/chrome/answer/95622?hl=en">Chrome</a> have had for awhile now, and it comes to Safari with a few idiosyncrasies you will want to familiarize yourself with.</p>
<h2>The Gist</h2>
<p>Pinned tabs in Safari work similarly to Chrome or Firefox. Open up a tab in Safari, pin it to your tab bar, and it will remain active in the background. This is most useful for sites that you routinely visit, and would rather keep open and running on the left side of your tab bar. There is currently no shortcut for this functionality, but you can command-click your tab and choose “Pin Tab” or accomplish this via Window → Pin Tab.</p>
<p><img src="/assets/pinned_tabs.png" alt="Pinned Tabs Example"></p>
<p>Once a tab is pinned, you cannot close it. Go ahead, give it a try. Nope, <code>⌘W</code> just takes you to the first un-pinned tab. Ixnay on File → Close Window as well, that might close the window, but open up another window and you’ll see you didn’t get very far. Well what about <code>⌘Q</code>? Surely if I quit the damn application all these pinned things are gone. Negative, now this is just getting annoying.</p>
<p>The only way to close a tab, once pinned, is to un-pin it. You can accomplish this via command-click, or venture back to Window → Unpin Tab.</p>
<h2>The Implementation</h2>
<p>On Chrome and Firefox, the pinned tabs use the websites <a href="https://en.wikipedia.org/wiki/Favicon">favicon</a> as its placeholder image in their respective tab bars. But this is Apple, and similar to the <a href="https://developer.apple.com/library/prerelease/ios/documentation/AppleApplications/Reference/SafariWebContent/ConfiguringWebApplications/ConfiguringWebApplications.html#//apple_ref/doc/uid/TP40002051-CH3-SW4">Web Clip icon</a>, they want you to add another <code>link</code> tag to your page header. </p>
<p>Without the additional markup, your site’s icon will appear as a square with the first letter of your domain capitialized. Safari does choose a color from your site as the background for this square, but it is still worth changing. <sup id="fnref2"><a href="#fn2" rel="footnote">2</a></sup></p>
<p>The format for the markup looks like the following:</p>
<div class="highlight"><pre><code class="language-html" data-lang="html"><span></span><span class="p"><</span><span class="nt">link</span> <span class="na">rel</span><span class="o">=</span><span class="s">"mask-icon"</span> <span class="na">href</span><span class="o">=</span><span class="s">"website_icon.svg"</span> <span class="na">color</span><span class="o">=</span><span class="s">"red"</span><span class="p">></span>
</code></pre></div>
<p>The image in question must be a 100% black vector image with a transparent background. Safari is pretty strict on this, try and use a color other than black, and you’ll be stuck with the default image. You can change the color of the non-transparent part of your <code>SVG</code> using the <code>color</code> attribute. It will take a hex value, RGB value, or a recognized color-keyword, such as <code>black</code>.</p>
<p>If you’re on a Mac and you need a good application for creating <code>SVG</code> images, take a look at <a href="http://www.sketchapp.com">Sketch 3</a>. Don’t let the price fool you, it’s very fair for the application you’re getting. And there is a trial on their website.</p>
<p>Safari does keep a cache of all the <code>mask-icon</code> images it comes across in <code>~/Library/Safari/Template Icons</code>. If you notice that your icon isn’t updating while you’re testing it, you might want to delete the contents of that folder and restart Safari. </p>
<p>That’s it! Drop that <code>SVG</code> in your root directory, add that tag to your page, and stare in awe at the amount of WebKit-specific tags in your header.</p>
<div class="footnotes">
<hr>
<ol>
<li id="fn1">
<p>And, Safari is the <a href="http://caniuse.com/#feat=css-backdrop-filter">first major browser</a> to implement the Backdrop filters outlined in a <a href="https://drafts.fxtf.org/filters-2/#BackdropFilterProperty">W3C draft</a> last fall. So much for <a href="http://nolanlawson.com/2015/06/30/safari-is-the-new-ie/">all that hype</a>. <a href="#fnref1" rev="footnote">↩</a></p>
</li>
<li id="fn2">
<p>Best I can tell, it uses the contents of the first element’s <code>background-color</code>. Although this is 100% guesswork based on limited to no facts. In other words, I’m positive that’s what it’s doing. <a href="#fnref2" rev="footnote">↩</a></p>
</li>
</ol>
</div>Pat GaffneySafari 9.0 shipped last week with the release of El Capitan. This version is largely a feature release – last year Safari got it’s root canal, now it’s time for a cleaning.Python in TextMate 22015-09-28T18:08:00-05:002015-09-28T18:08:00-05:00http://hypepat.com/2015/python-in-textmate<p>The true dominance of <a href="http://macromates.com">TextMate</a> lies in its <a href="http://manual.macromates.com/en/bundles#bundles">bundles</a>. No matter what language you prefer to spend your time writing, chances are, there exists a bundle that is feature-packed with the idioms, syntax, and completions of that language.</p>
<p>TextMate ships with a <a href="https://github.com/textmate/python.tmbundle">Python bundle</a>, and it contains a multitude of <em>already</em> useful commands. <sup id="fnref1"><a href="#fn1" rel="footnote">1</a></sup> But, alas, it’s “Run Script” command, invoked with <code>⌘R</code>, refuses to cooperate with me. TextMate chooses to use the default installation of Python that <a href="http://docs.python-guide.org/en/latest/starting/install/osx/">ships with OS X</a>. To get specific, this is version 2.7.10 on El Capitan. This is a problem because I have decided to <a href="https://wiki.python.org/moin/Python2orPython3">forgo living in the past</a>, and otherwise embrace the future that is Python 3.</p>
<h2>#!/use/the/shebang</h2>
<p>TextMate will parse the first line of your Python script for a <a href="http://en.wikipedia.org/wiki/Shebang_%28Unix%29">shebang</a> sequence. If found, it will attempt to call that interpreter when you run your script. I have installed Python 3 using <a href="http://brew.sh">homebrew</a>, so the binary is in my <code>/usr/local/bin</code> folder. Lets set up a simple script and test this:</p>
<div class="highlight"><pre><code class="language-python" data-lang="python"><span></span><span class="ch">#!/usr/local/bin/python3</span>
<span class="k">print</span><span class="p">(</span><span class="s1">'hello, hypepat!'</span><span class="p">)</span>
</code></pre></div>
<p><img src="/assets/hello_hypepat.png" alt=""hello, hypepat!""></p>
<p>Excellent, it worked. It did everything I wanted: </p>
<ul>
<li>use the <code>python3</code> interpreter</li>
<li>don’t leave TextMate to find the terminal</li>
<li>print to a new window <sup id="fnref2"><a href="#fn2" rel="footnote">2</a></sup></li>
</ul>
<p>But, this is not very pragmatic. We shouldn’t have to rely on the shebang line to find the interpreter. Surely TextMate provides a way to find the interpreter I want, on an application-wide basis.</p>
<h2>Rage Against the Defaults</h2>
<p>First some background: TextMate uses <a href="http://manual.macromates.com/en/environment_variables">environment variables</a> to provide context to its various scripts and commands, including those in bundles. <a href="http://manual.macromates.com/en/environment_variables#dynamic_variables"><strong>Dynamic variables</strong></a> are defined by TextMate and provide the current configuration of the application. <sup id="fnref3"><a href="#fn3" rel="footnote">3</a></sup> <a href="http://manual.macromates.com/en/environment_variables#static_variables"><strong>Static variables</strong></a> are defined by the user in Preferences → Variables and give application-wide support to commands and snippets. Finally, <a href="http://manual.macromates.com/en/environment_variables#project_dependent_variables"><strong>Project dependent variables</strong></a> are defined by the user in their project configuration file, and exist only for snippets and commands executed in the context of that project.</p>
<p>Now, if we were to do some digging into the internals of the Python bundle, <sup id="fnref4"><a href="#fn4" rel="footnote">4</a></sup> we will find a Ruby script that is called every time we run our code. Line #13 of that script actually calls the Python interpreter to run our script, and the code looks alot like the following:</p>
<div class="highlight"><pre><code class="language-ruby" data-lang="ruby"><span></span><span class="no">TextMate</span><span class="o">::</span><span class="no">Executor</span><span class="o">.</span><span class="n">run</span><span class="p">(</span><span class="no">ENV</span><span class="o">[</span><span class="s2">"TM_PYTHON"</span><span class="o">]</span> <span class="o">||</span> <span class="s2">"python"</span><span class="p">,</span> <span class="s2">"-u"</span><span class="p">,</span> <span class="no">ENV</span><span class="o">[</span><span class="s2">"TM_FILEPATH"</span><span class="o">]</span> <span class="o">...</span>
</code></pre></div>
<p>It appears there is a static variable, <code>TM_PYTHON</code>, that is either set to the OS X system interpreter, or isn’t set at all. We could update the <code>"python"</code> after the logical-or to <code>"python3"</code>, but this single line is going to be executed for every script we run in the future. And to be honest, there is more Python 2 code than Python 3 code in the world, so that seems like a rash thing to do.</p>
<p>Instead, lets assign a value to <code>TM_PYTHON</code>. Static variables are assigned in Preferences → Variables. Hit the <code>+</code> and enter <code>TM_PYTHON</code> for the “Variable Name”. Now we can enter the absolute path to our <code>python3</code> interpreter, as we did above with the shebang line. Go ahead an enter <code>/usr/local/bin/python3</code> for the “Value” of the variable. Rerun the script, and marvel at your command of a very powerful editor. </p>
<p>Now, go back and disable (uncheck) the static variable <code>TM_PYTHON</code> in Preferences → Variables, and lets try something perhaps a little more elegant.</p>
<h2>A Product of the Environment</h2>
<p>In most cases manually changing the value of <code>TM_PYTHON</code> is not the most elegant solution, as we are limiting ourselves to the use of only one interpreter. And considering the <em>vast</em> majority of Python development is done in <a href="http://virtualenv.readthedocs.org/en/latest/">virtual environments</a>, this is not an option.</p>
<p>Virtual environments work by <strong>prefixing</strong> your <code>$PATH</code> shell variable with the location of a locally installed Python interpreter and library. <sup id="fnref5"><a href="#fn5" rel="footnote">5</a></sup> This way, when you run your scripts, they call the <code>python</code> that was installed through <a href="http://virtualenv.readthedocs.org/en/latest/"><code>virtualenv</code></a>. This allows the developer to create specific environments with specific dependencies. Traditionally, the developer would use <code>/usr/bin/env</code> instead of an absolute path to specify the first interpreter found along the <code>$PATH</code>.</p>
<p>So, lets backtrack a bit and re-examine that shebang line. We can change it from <code>/usr/local/bin/python3</code>, the absolute path, to <code>/usr/bin/env python3</code>, the environment variable.</p>
<div class="highlight"><pre><code class="language-python" data-lang="python"><span></span><span class="ch">#!/usr/bin/env python3</span>
<span class="k">print</span><span class="p">(</span><span class="s1">'hello, hypepat!'</span><span class="p">)</span>
</code></pre></div>
<p><img src="/assets/mate_path_error.png" alt="TextMate path error"></p>
<p>Damn it. Although our <code>$PATH</code> variable is set, TextMate <a href="http://blog.macromates.com/2014/defining-a-path/">does not parse our shell scripts</a>. In other words, TextMate doesn’t have any idea what our <code>$PATH</code> variable is set to, because it doesn’t share environment variables with the shell. It exports the dynamic, static, and project-dependent variables when a command is issued from within the editor, as needed. <sup id="fnref6"><a href="#fn6" rel="footnote">6</a></sup></p>
<p>Fortunately, we can assign our <code>$PATH</code> variable to be recognized in TextMate. Venture back to Preferences → Variables and add a variable with the name <code>$PATH</code> and the value <code>$PATH:/usr/local/bin</code>. <sup id="fnref7"><a href="#fn7" rel="footnote">7</a></sup> Now, running our script again should be successful. <sup id="fnref8"><a href="#fn8" rel="footnote">8</a></sup></p>
<p>Now TextMate is dynamically pointing at the first Python 3 interpreter in our <code>$PATH</code>. This is okay, but it isn’t a great solution. For example, if we were to edit our <code>$PATH</code>, perhaps by entering a <code>virtualenv</code>, TextMate would have no idea. Thus, we have more work to do.</p>
<h2>Configuring the Configuration</h2>
<p>Exit: frustration, enter: <a href="http://blog.macromates.com/2011/git-style-configuration/">TextMate preferences</a>! TextMate allows us to create project-specific settings under the umbrella of a <code>.tm_properties</code> file. You may remember “project dependent variables” from eariler. These are just what we need to make our solution virtual-environment-proof.</p>
<p>First, a few basics on these preferences files. To start, all we need to do is dump a <code>.tm_properties</code> file into the root directory of our project. In fact, any folder that has a <code>.tm_properties</code> overrides any <em>parent</em> folder with a properties file. In other words, you can nest these files in your projects to specify settings on a folder-level. And considering TextMate 2 treats every folder as a project, the possibilities are really endless.</p>
<p>After opening that file in TextMate, you will see that it has enabled the “TextMate Settings” language syntax. These settings work just as basic assignments, but their power is in their override-ability. Any <em>global</em> settings you have set up in Preferences → Variables can be overridden in this file, as your specific project calls for it.</p>
<p>Lets see a simple example:</p>
<div class="highlight">
<pre>
<span class="k">TM_PYTHON </span><span class="o">= </span><span class="s">"</span><span class="se">${CWD}</span><span class="s">/venv/bin/python"</span>
<span class="k">excludeDirectoriesInBrowser </span><span class="o">= </span><span class="s">"{__pycache__,include,lib,bin}"</span>
<span class="k">includeFilesInBrowser </span><span class="o">= </span><span class="s">"{.gitignore}"</span>
<span class="o">[ </span><span class="sx">source.python</span><span class="o"> ]</span>
<span class="k">softTabs </span><span class="o">= </span><span class="bp">true</span>
<span class="k">tabSize </span><span class="o">= </span><span class="m">4</span>
</pre>
</div>
<p>The first setting overrides the global <code>TM_PYTHON</code> variable we assigned earlier to use an interpreter that is located in a subfolder of our current working directory, or <code>${CWD}</code>. If you are using <code>virtualenv</code>, the “venv” folder contains your python interpreter along with all its libraries. If you name your virtual environments, then this folder will bear that same name.</p>
<p>The second and third lines tell TextMates file browser to exclude and include specific files for this project. <a href="https://en.wikipedia.org/wiki/CPython">CPython</a> often utilizes cache files to optimize code, and I am choosing to have these files excluded from cluttering up my file brower. Also, I would like to see my “.gitignore” file in the browser, but because it is a <a href="https://en.wikipedia.org/wiki/Hidden_file_and_hidden_directory#Mac_OS_X">hidden file</a>, it is excluded by default. You can see just how powerful these <code>.tm_properties</code> are with a few settings.</p>
<p>Finally, Python takes a very strict stance on whitespace. No matter your feelings on this, we need to make sure that indentation is four spaces. We can set global settings in this file for all files of the project that have a specific syntax, using the <code>source.«language»</code> modifier.</p>
<p>There are <a href="http://wiki.macromates.com/Reference/Settings">tons of possible settings</a>, and if you’re short on ideas you can checkout the <a href="http://wiki.macromates.com/Reference/FolderSpecificSettings">default settings</a>.</p>
<p>Using these settings files we can pin down the exact location of our python interpreter, without listing an absolute path in the shebang line. This also keeps us from manually changing our <code>TM_PYTHON</code> static variable each time we switch virtual environments. The creation of these files can even be strung together with the <code>virtualenv</code> command to create a virtual environment and specify the settings for the editor all in one command.</p>
<div class="footnotes">
<hr>
<ol>
<li id="fn1">
<p>Which, after having a look at some of the <a href="https://chocolatapp.com">competition</a>, is TextMate’s biggest draw for me to continue using it even after its… <a href="http://blog.macromates.com/2012/textmate-2-at-github/">retirement</a>? Hell, I’m not even sure what to call it. <a href="#fnref1" rev="footnote">↩</a></p>
</li>
<li id="fn2">
<p>The default settings for TextMate show the output on the right of the window in a drawer, but this resizes the editor, and we can’t have that. Better to have it in a pop-up that we can quickly <code>⌘W</code> and get back to our code. Plus the pop-up window works great in full-screen mode. Change this setting in Preferences → Projects. <a href="#fnref2" rev="footnote">↩</a></p>
</li>
<li id="fn3">
<p>AKA: they are <em>implictly</em> changed by the user, just by altering the state of the application. <a href="#fnref3" rev="footnote">↩</a></p>
</li>
<li id="fn4">
<p>You can edit bundles by going to Bundles → Edit Bundles, or <code>^⌥⌘B</code>. <a href="#fnref4" rev="footnote">↩</a></p>
</li>
<li id="fn5">
<p><em>Locally</em> meaning “usually inside your current working directory”, or otherwise specified when you created the virtual environment. Unless of course, you’re using <a href="http://virtualenvwrapper.readthedocs.org/en/latest/"><code>virtualenvwrapper</code></a>, in which case “usually inside a hidden folder in your home directory.” <a href="#fnref5" rev="footnote">↩</a></p>
</li>
<li id="fn6">
<p>If you didn’t get an error here, that’s fine. It just means you didn’t uncheck your <code>TM_PYTHON</code> variable earlier. You can continue along just the same. <a href="#fnref6" rev="footnote">↩</a></p>
</li>
<li id="fn7">
<p>I am keeping <code>/usr/local/bin</code> in my <code>$PATH</code> because I use homebrew to install programs, and that’s where it installs them. If you are using <a href="http://www.macports.org">MacPorts</a> (then switch to homebrew…) then you will use <code>$PATH:/opt/local/bin</code>. <a href="#fnref7" rev="footnote">↩</a></p>
</li>
<li id="fn8">
<p>If you are getting a <code>$PATH</code> related error still, you probably need to update your path variable. Depending on which login shell you prefer, you can probably update the <code>$PATH</code> in your <a href="http://hyperpolyglot.org/unix-shells#startup-file">startup files</a>. <a href="#fnref8" rev="footnote">↩</a></p>
</li>
</ol>
</div>Pat GaffneyThe true dominance of TextMate lies in its bundles. No matter what language you prefer to spend your time writing, chances are, there exists a bundle that is feature-packed with the idioms, syntax, and completions of that language.