<rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Developer-Tools | AkitaOnRails.com</title><link>https://akitaonrails.github.io/en/tags/developer-tools/</link><description>Fabio Akita's blog — tech, career, and assorted geek topics. English edition.</description><generator>Hugo -- gohugo.io</generator><language>en</language><lastBuildDate>Mon, 19 Oct 2026 23:20:51 +0000</lastBuildDate><atom:link href="https://akitaonrails.github.io/en/tags/developer-tools/index.xml" rel="self" type="application/rss+xml"/><item><title>Playing with TUIs and LLMs - Ratatui+Bubbletea</title><link>https://akitaonrails.github.io/en/2026/06/08/playing-with-tuis-llms-ratatui-bubbletea/</link><guid isPermaLink="true">https://akitaonrails.github.io/en/2026/06/08/playing-with-tuis-llms-ratatui-bubbletea/</guid><pubDate>Mon, 08 Jun 2026 16:00:00 -0300</pubDate><description>&lt;p&gt;Before getting to the new toy, a quick reminder: &lt;a href="https://github.com/akitaonrails/ai-jail"target="_blank" rel="noopener"&gt;ai-jail&lt;/a&gt; and &lt;a href="https://github.com/akitaonrails/ai-memory"target="_blank" rel="noopener"&gt;ai-memory&lt;/a&gt; are still getting plenty of attention. Issues, pull requests, small fixes, packaging improvements, environment bugs, documentation tweaks. The stuff nobody sees in a launch post, but that turns an experiment into something you can use every day.&lt;/p&gt;
&lt;p&gt;I like this phase. The project stops being &amp;ldquo;what I imagined in my setup&amp;rdquo; and becomes &amp;ldquo;what breaks on somebody else&amp;rsquo;s machine.&amp;rdquo; Then Windows shows up. macOS. Arch. AUR. Weird paths. Tokens saved somewhere else. Different shell. Different terminal. Annoying? Yes. Necessary? Also yes.&lt;/p&gt;</description><content:encoded><![CDATA[<p>Before getting to the new toy, a quick reminder: <a href="https://github.com/akitaonrails/ai-jail"target="_blank" rel="noopener">ai-jail</a> and <a href="https://github.com/akitaonrails/ai-memory"target="_blank" rel="noopener">ai-memory</a> are still getting plenty of attention. Issues, pull requests, small fixes, packaging improvements, environment bugs, documentation tweaks. The stuff nobody sees in a launch post, but that turns an experiment into something you can use every day.</p>
<p>I like this phase. The project stops being &ldquo;what I imagined in my setup&rdquo; and becomes &ldquo;what breaks on somebody else&rsquo;s machine.&rdquo; Then Windows shows up. macOS. Arch. AUR. Weird paths. Tokens saved somewhere else. Different shell. Different terminal. Annoying? Yes. Necessary? Also yes.</p>
<p>But today&rsquo;s main dish is not ai-jail or ai-memory. It&rsquo;s TUI. More specifically, my recent habit of writing small terminal tools in Rust with <a href="https://ratatui.rs/"target="_blank" rel="noopener">Ratatui</a>, while wanting them to look like <a href="https://github.com/charmbracelet/bubbletea"target="_blank" rel="noopener">Bubble Tea</a>.</p>
<h2>The app I won&rsquo;t open<span class="hx:absolute hx:-mt-20" id="the-app-i-wont-open"></span>
    <a href="#the-app-i-wont-open" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Over the last few weeks I also worked on a private project I do not plan to open source. It&rsquo;s a TUI to track my US bank account, investments, assets, positions, covered calls, open calls, all that boring grown-up stuff. I won&rsquo;t publish the code because this tool was born glued to my financial workflow, my spreadsheets, my statements, and my internal hacks. Opening it would turn a tool for myself into free support for other people&rsquo;s bank bugs. No thanks.</p>
<p>But I can show the general look. I censored what needed censoring:</p>
<p><strong>Obvious note, but I&rsquo;ll make it explicit: every value, ticker, position, and date shown in the screenshot is bogus demonstration data. It is not real account data, not my real portfolio, and not investment advice.</strong></p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/06/08/ratatui-bubbletea/private-portfolio-censored.png" alt="Private portfolio TUI in a terminal, with dashboard tabs and a holdings table. The bank name was censored."  loading="lazy" /></p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/06/08/ratatui-bubbletea/private-allocation-censored.png" alt="Private TUI showing an asset allocation view, with sensitive names censored."  loading="lazy" /></p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/06/08/ratatui-bubbletea/private-open-calls-censored.png" alt="Private TUI showing an open calls tab with bogus demonstration data and sensitive names censored."  loading="lazy" /></p>
<p>Every time I build a small TUI, the same question comes back: what stack should I use?</p>
<p>If I were writing everything by hand, I would probably pick Python or Go. They are more comfortable for this kind of small utility. Python because it is direct, full of libraries, great for scripts that talk to APIs and parse JSON. Go because it produces simple binaries, cross-platform support is sane, and the CLI ergonomics are good.</p>
<p>But today I rarely write all that code by hand. I orchestrate Claude, Codex, OpenCode, ask for reviews, ask for refactors, ask for tests. In that setup, Rust&rsquo;s lack of ergonomics hurts less, because the LLM is the one fighting the borrow checker, trait bounds, and annoying lifetimes. I stay closer to reviewer and end user. And then Rust starts looking very attractive.</p>
<p>Good tooling. <code>cargo</code> is great. Tests are easy to run. Cross compile is manageable. The final binary is clean. Dumb memory bugs mostly disappear. I am not saying Rust is magically better than Go or Python for every TUI. It isn&rsquo;t. But with an LLM writing most of it, the cost that would usually make me avoid Rust drops a lot. And current models are surprisingly competent with Rust, as long as you make them run tests, fix warnings, and you don&rsquo;t accept the first version as if Moses brought it down from the mountain.</p>
<h2>Ratatui is good, but I wanted the Charm look<span class="hx:absolute hx:-mt-20" id="ratatui-is-good-but-i-wanted-the-charm-look"></span>
    <a href="#ratatui-is-good-but-i-wanted-the-charm-look" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p><a href="https://ratatui.rs/"target="_blank" rel="noopener">Ratatui</a> is a Rust library for building full terminal interfaces: dashboards, interactive apps, tables, lists, gauges, layouts, the whole thing we used to call &ldquo;modern ncurses.&rdquo; It grew out of <code>tui-rs</code>, and today it is probably the obvious path if you want to build a serious TUI in Rust.</p>
<p>Ratatui works well. My problem is taste: by default, I don&rsquo;t find it pretty. Not ugly in the &ldquo;this looks like a DOS program from 1993&rdquo; sense. You can build good-looking stuff with it. But many Ratatui TUIs fall into that square, gray, functional look, like a datacenter admin panel.</p>
<p>I like the <a href="https://charm.sh/"target="_blank" rel="noopener">Charmbracelet</a> vibe more. <code>gum</code>, for example, is a collection of commands that make shell scripts interactive without turning them into a festival of <code>read -p</code> and <code>case</code>. Prompt, select, filter, spinner, table, pager, styling. You can make a bash script feel like a decent app in minutes.</p>
<p>And then there is <a href="https://github.com/charmbracelet/bubbletea"target="_blank" rel="noopener">Bubble Tea</a>, in Go, inspired by Elm architecture. You have a model, receive messages, update state, render a view. Simple idea, very good fit for terminal apps: state comes in, event comes in, view goes out. Charm also has visual taste I like: good colors, decent spacing, light components, nothing that looks like a WinForms form thrown into a terminal.</p>
<p>So I wanted this: stay in Rust with Ratatui, but steal the feeling of Bubble Tea. Not the whole runtime. Not a perfect clone. Just the visual direction and a few components.</p>
<p>That is how <a href="https://github.com/akitaonrails/ratatui-bubbletea"target="_blank" rel="noopener">ratatui-bubbletea</a> was born.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/06/08/ratatui-bubbletea/ratatui-bubbletea-example.png" alt="ratatui-bubbletea demo running in a terminal, with SelectList, Spinner, Theme, ThemedTable, TextInput, Progress, and Viewport in a Charm-like style."  loading="lazy" /></p>
<p>The project does not replace Ratatui. It sits on top. The idea is to offer a theme and component layer inspired by Bubble Tea/Bubbles, while still rendering through Ratatui.</p>
<p>Right now it is split into crates:</p>
<ul>
<li><code>ratatui-bubbletea-theme</code>, with palette, helpers, and shared styles.</li>
<li><code>ratatui-bubbletea-components</code>, with ready-made components like select list, spinner, progress, table, text input, viewport, and help.</li>
<li><code>ratatui-tea</code>, optional, for people who want ergonomics closer to <code>Model</code>, <code>Msg</code>, and <code>Cmd</code>, without pretending Rust became Go.</li>
</ul>
<p>The README has the full examples and documentation for what exists today. For now, I treat it as a small toolkit. It serves my apps, and if it serves somebody else, fine. If it doesn&rsquo;t, no drama either. The goal was to stop reimplementing the same theme and the same widgets every time I started a new TUI.</p>
<h2>ai-usagebar as the public example<span class="hx:absolute hx:-mt-20" id="ai-usagebar-as-the-public-example"></span>
    <a href="#ai-usagebar-as-the-public-example" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Since I won&rsquo;t open the financial app, I needed a public example using this aesthetic. So I updated my <a href="https://github.com/akitaonrails/ai-usagebar"target="_blank" rel="noopener">ai-usagebar</a>.</p>
<p>If you don&rsquo;t remember it, I explained the project in <a href="/en/2026/05/24/i-built-a-waybar-widget-for-omarchy-to-monitor-llm-usage-ai-usagebar/">&ldquo;I Built a Waybar Widget for Omarchy to Monitor LLM Plan Usage: ai-usagebar&rdquo;</a>. It started as a Waybar widget to show LLM plan usage: Claude, OpenAI Codex/ChatGPT, Z.AI, OpenRouter. One glance at the bar and I know whether I am close to the limit and which vendor to use next.</p>
<p>Later it also became a standalone TUI. And thanks to contributions, it now supports Windows too. That is funny because its origin is completely Linux/Omarchy/Waybar. But that is open source: somebody uses it in another environment, finds friction, sends a PR, and now the project is a little less provincial.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/06/08/ratatui-bubbletea/ai-usagebar.png" alt="ai-usagebar in TUI mode showing an OpenAI usage dashboard, vendor tabs, limit gauges, and footer shortcuts."  loading="lazy" /></p>
<p>In ai-usagebar, the visual change will not alter anybody&rsquo;s life. It is a simple screen. Tabs, gauges, text, shortcuts. But it is a good example because it is small, real, tested, packaged, and does not depend on my private app. You can look at the code and see how I applied the theme layer.</p>
<h2>The scratch-my-own-itch apps<span class="hx:absolute hx:-mt-20" id="the-scratch-my-own-itch-apps"></span>
    <a href="#the-scratch-my-own-itch-apps" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>All these projects follow the same logic: I have an itch, I make a small tool, I use it, adjust it, package it. No startup roadmap. No manifesto. Just a tool that fixes something annoying in my own setup.</p>
<p>One recent example is <a href="https://github.com/akitaonrails/clock-tui"target="_blank" rel="noopener">clock-tui</a>. It did not start with me. It was an old Rust project, <code>tclock</code>, that looked abandoned. I wanted a big clock on my second vertical monitor. That monitor sits on the side, and I like having a huge desk clock taking up part of the screen. I used the original clock-tui for a while.</p>
<p>But an entire vertical screen just to show the time is wasteful. I already had <a href="https://github.com/akitaonrails/ghpending"target="_blank" rel="noopener">ghpending</a>, which lists open issues and PRs across all my projects. It is my &ldquo;is anybody waiting for an answer?&rdquo; in CLI form. I also wanted to see my agenda.</p>
<p>So I made another small app: <a href="https://github.com/akitaonrails/google-calendar-tui"target="_blank" rel="noopener">google-calendar-tui</a>. It uses the Gmail accounts already registered in GNOME Online Accounts and summarizes my upcoming appointments in the terminal. Read-only. No new OAuth ritual. No extra secret config scattered somewhere weird.</p>
<p>With those two pieces, I modernized clock-tui and added auto-refreshing widget layout support. Now the clock takes the screen the way I wanted, but around it I also get GitHub pending work and Google Calendar appointments.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/06/08/ratatui-bubbletea/tclock.png" alt="tclock on a vertical monitor, with a large clock, GitHub pending widget on the left, and Google Calendar agenda on the right."  loading="lazy" /></p>
<p>This is exactly the kind of thing I would never build if it cost me an entire weekend. But with an LLM, it becomes a sequence of small tasks: read the old project, modernize dependencies, run tests, add a widget module, call ghpending, call google-calendar-tui, organize layout, fix bugs, package. It still takes work. But it is supervision and refinement work, not fighting boilerplate.</p>
<h2>Tweaking Geary without a fork<span class="hx:absolute hx:-mt-20" id="tweaking-geary-without-a-fork"></span>
    <a href="#tweaking-geary-without-a-fork" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Another itch came from GNOME.</p>
<p>Since I wanted to centralize my accounts in GNOME Online Accounts, I started using <a href="https://wiki.gnome.org/Apps/Geary"target="_blank" rel="noopener">Geary</a> and GNOME Calendar on the second monitor too. I like the idea: accounts configured once, desktop apps reusing the same infrastructure, no tiny program inventing its own login flow.</p>
<p>The problem is that Geary has a fixed three-column layout. On a normal screen, fine. On a vertical monitor, it gets cramped. The folder column, message list, and email body fight for space. I did not want to maintain a Geary fork just to hide a sidebar. Forking a large GTK app is debt. You blink and spend the rest of your life resolving merge conflicts.</p>
<p>So I made a GTK module: <a href="https://github.com/akitaonrails/geary-hide-sidebar-module"target="_blank" rel="noopener">geary-hide-sidebar-module</a>. It injects behavior into Geary at runtime and lets me collapse/expand the sidebar, with a shortcut and auto-collapse for narrow windows. No rebuilding Geary. No fork to maintain. Just a small module with one very specific job.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/06/08/ratatui-bubbletea/geary-sidebar-hidden.png" alt="Geary with the sidebar collapsed, showing the email list and message body in a more comfortable layout for a vertical screen."  loading="lazy" /></p>
<p>This is a good lesson: sometimes you do not need to fork the whole application. You can adjust it from the outside. GTK_MODULES exists. Wrappers exist. Config exists. CSS exists. Scripts exist. Not every customization has to become eternal maintenance of somebody else&rsquo;s code.</p>
<h2>Small code got cheap<span class="hx:absolute hx:-mt-20" id="small-code-got-cheap"></span>
    <a href="#small-code-got-cheap" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>That is why I keep insisting on this idea of small apps. With current LLMs, it became very easy to implement a specific idea to make your environment fit your needs. No waiting for someone else to have the exact same pain. No searching GitHub for three hours for a tool that does 80% of what you want and 40% of what you don&rsquo;t want.</p>
<p>You describe the itch, create a repo, ask for a prototype, test it, ask for refactoring, ask for tests, ask for packaging. If it sucks, throw it away. If it works, install it and use it.</p>
<p>I do not let this turn into random junk dumped in <code>~/bin</code> with no owner. My apps have tests. They have automated builds. Many have GitHub releases, AUR packages, normal installation with <code>yay</code> on Arch. They use XDG paths, so config goes to <code>~/.config</code>, cache goes to <code>~/.cache</code>, data goes to <code>~/.local/share</code>. Organized. Upgradable. Removable. Something another person can clone and contribute to.</p>
<p>Here are all the links in one place:</p>
<ul>
<li><a href="https://github.com/akitaonrails/ratatui-bubbletea"target="_blank" rel="noopener">ratatui-bubbletea</a></li>
<li><a href="https://github.com/akitaonrails/ai-usagebar"target="_blank" rel="noopener">ai-usagebar</a></li>
<li><a href="https://github.com/akitaonrails/clock-tui"target="_blank" rel="noopener">clock-tui</a></li>
<li><a href="https://github.com/akitaonrails/ghpending"target="_blank" rel="noopener">ghpending</a></li>
<li><a href="https://github.com/akitaonrails/google-calendar-tui"target="_blank" rel="noopener">google-calendar-tui</a></li>
<li><a href="https://github.com/akitaonrails/geary-hide-sidebar-module"target="_blank" rel="noopener">geary-hide-sidebar-module</a></li>
<li><a href="https://github.com/akitaonrails/ai-jail"target="_blank" rel="noopener">ai-jail</a></li>
<li><a href="https://github.com/akitaonrails/ai-memory"target="_blank" rel="noopener">ai-memory</a></li>
</ul>
<p>If you use any of them and it breaks in your setup, open an issue. If you know how to fix it, send a PR. I actually use these tools, so useful bug reports tend to turn into fixes fast.</p>
<p>My practical rule is this: customize your environment without turning everything into duct tape. Build small tools. Test them. Package them. Document them. Let the LLM carry the boring weight and use your brain to decide what is worth keeping.</p>
<p>That is the fun part of programming that had gone missing for a bit. Now it is back.</p>
]]></content:encoded><category>ai-usagebar</category><category>developer-tools</category><category>rust</category><category>open-source</category></item><item><title>I Built a Waybar Widget for Omarchy to Monitor LLM Plan Usage: ai-usagebar</title><link>https://akitaonrails.github.io/en/2026/05/24/i-built-a-waybar-widget-for-omarchy-to-monitor-llm-usage-ai-usagebar/</link><guid isPermaLink="true">https://akitaonrails.github.io/en/2026/05/24/i-built-a-waybar-widget-for-omarchy-to-monitor-llm-usage-ai-usagebar/</guid><pubDate>Sun, 24 May 2026 00:01:00 -0300</pubDate><description>&lt;p&gt;Anyone following the blog already knows I use a whole bunch of different LLM vendors. The main ones are Claude and GPT, via Claude Code and Codex. I use each one&amp;rsquo;s harness because I&amp;rsquo;m locked into their subscription plans (Pro, Plus, Max), which come out way cheaper than paying per-token credits like OpenRouter. Even so, I also use OpenRouter to reach other models for testing, and I even have a Z.AI GLM subscription for small stuff.&lt;/p&gt;</description><content:encoded><![CDATA[<p>Anyone following the blog already knows I use a whole bunch of different LLM vendors. The main ones are Claude and GPT, via Claude Code and Codex. I use each one&rsquo;s harness because I&rsquo;m locked into their subscription plans (Pro, Plus, Max), which come out way cheaper than paying per-token credits like OpenRouter. Even so, I also use OpenRouter to reach other models for testing, and I even have a Z.AI GLM subscription for small stuff.</p>
<p>The problem with juggling several plans is keeping track of how much I&rsquo;ve burned on each. I&rsquo;d been using <a href="https://github.com/mryll/claudebar"target="_blank" rel="noopener">claudebar</a>, a Waybar widget that shows your Anthropic plan usage. I like it, but I wanted to see all my vendors in one place, glance at it and know where I stand. And I didn&rsquo;t want to clutter my Waybar with a separate widget per vendor. So I built my own: <strong><a href="https://github.com/akitaonrails/ai-usagebar"target="_blank" rel="noopener">ai-usagebar</a></strong>.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/05/24/ai-usagebar/ai-usagebar-waybar.png" alt="Waybar widget showing “cld 29% · 1h 12m” in the top-right corner, with the tooltip open showing the Claude Max 20x plan: Session 29%, Weekly 47%, Sonnet only 0%, Extra usage $0.00 against a $1100 limit, and the last-updated time."  loading="lazy" /></p>
<p>It&rsquo;s a Rust port of claudebar, drop-in compatible, extended to four vendors: Anthropic Claude, OpenAI Codex/ChatGPT, Z.AI (GLM), and OpenRouter. It keeps the same flags (<code>--icon</code>, <code>--format</code>, <code>--tooltip-format</code>, etc.), the same minimalist Pango-bordered tooltip, and the same Omarchy theme auto-detection. The difference is that now all four vendors show up in the same place, instead of 865 lines of bash babysitting just one.</p>
<h2>How it authenticates with each vendor<span class="hx:absolute hx:-mt-20" id="how-it-authenticates-with-each-vendor"></span>
    <a href="#how-it-authenticates-with-each-vendor" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>This is the part worth explaining, because each vendor does it differently. Claude and Codex use OAuth: their official CLIs (<code>claude</code> and <code>codex</code>) already wrote the credentials to disk when you logged in, and ai-usagebar reads those same files. No environment variable needed, the token even refreshes itself.</p>
<p>Z.AI and OpenRouter use API keys, so for those you need to set a key (via env var or inline in the config).</p>
<table>
  <thead>
      <tr>
          <th>Vendor</th>
          <th>Method</th>
          <th>What you need to do</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Anthropic</td>
          <td>OAuth, reads from <code>~/.claude/.credentials.json</code></td>
          <td>Run <code>claude</code> once to log in. Token refreshes itself.</td>
      </tr>
      <tr>
          <td>OpenAI</td>
          <td>OAuth, reads from <code>~/.codex/auth.json</code></td>
          <td>Run <code>codex login</code> once. Token refreshes itself.</td>
      </tr>
      <tr>
          <td>Z.AI</td>
          <td>API key (<code>ZAI_API_KEY</code> or <code>[zai] api_key</code> in config)</td>
          <td>Set either one.</td>
      </tr>
      <tr>
          <td>OpenRouter</td>
          <td>API key (<code>OPENROUTER_API_KEY</code> or <code>[openrouter] api_key</code>)</td>
          <td>Set either one.</td>
      </tr>
  </tbody>
</table>
<h2>The interface beyond Waybar<span class="hx:absolute hx:-mt-20" id="the-interface-beyond-waybar"></span>
    <a href="#the-interface-beyond-waybar" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Besides the widget on the bar, there&rsquo;s a tabbed TUI (<code>ai-usagebar-tui</code>) to see everything at once. Navigate with Tab / h / l between vendors, auto-refresh every 60s. You can open it by clicking the Waybar widget, or run it straight from the terminal (more on that in the next section).</p>
<p>The OpenRouter tab shows credit balance, today/week/month spend, and the tier:</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/05/24/ai-usagebar/ai-usagebar-tui-openrouter.png" alt="ai-usagebar-tui on the OpenRouter tab: credit-balance gauge at 98% in red ($13.67 left of $900), usage-by-period block (today/week/month), paid tier."  loading="lazy" /></p>
<p>And there&rsquo;s a settings overlay to pick the primary vendor and paste the API keys without editing the config by hand:</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/05/24/ai-usagebar/ai-usagebar-tui-settings.png" alt="Settings overlay floating over the TUI: primary-vendor radio (Anthropic selected), masked Z.AI API key (•••), masked OpenRouter API key (•••), Save button, key hints in the footer."  loading="lazy" /></p>
<h2>Not on Omarchy or Hyprland? Run it as a standalone TUI<span class="hx:absolute hx:-mt-20" id="not-on-omarchy-or-hyprland-run-it-as-a-standalone-tui"></span>
    <a href="#not-on-omarchy-or-hyprland-run-it-as-a-standalone-tui" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>The Waybar widget is optional. The two binaries are independent, so if you don&rsquo;t run Omarchy, or Hyprland, or Waybar (or you just prefer to check usage now and then instead of having it on the bar all the time), <code>ai-usagebar-tui</code> works as a fully standalone terminal app:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">ai-usagebar-tui    <span class="c1"># opens in your current terminal</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>It runs in any terminal emulator (Kitty, Alacritty, Foot, Ghostty, etc.), works even over a plain SSH session, and doesn&rsquo;t depend on a compositor or any window-manager feature. All the controls and the settings overlay work the same. Same four vendors, same tabs:</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/05/24/ai-usagebar/ai-usagebar-tui-openai.png" alt="ai-usagebar-tui on the OpenAI tab running in a terminal: Codex 5h and weekly gauges, Credits block with message-count ranges, Claude / OpenAI / GLM (Z.AI) / OpenRouter tabs at the top, key hints in the footer."  loading="lazy" /></p>
<p>Typical use off Omarchy: a quick check before starting a long session (&ldquo;am I close to my Claude weekly limit?&rdquo;), a monitor in a tmux pane while you code, or a shell-only tool on a remote machine (install the binary and that&rsquo;s it, no Waybar or Hyprland dependency). The TUI is the canonical way to see all four vendors at once, whether or not you ever set up the widget.</p>
<h2>Install<span class="hx:absolute hx:-mt-20" id="install"></span>
    <a href="#install" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>On Arch there&rsquo;s an AUR package, two flavors:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">yay -S ai-usagebar-bin    <span class="c1"># prebuilt binary from GitHub Releases (~5s)</span>
</span></span><span class="line"><span class="cl">yay -S ai-usagebar        <span class="c1"># compiles from source (~30-60s)</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Or straight from source:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">cargo build --release
</span></span><span class="line"><span class="cl">sudo make install                  <span class="c1"># → /usr/local/bin</span>
</span></span><span class="line"><span class="cl"><span class="c1"># or</span>
</span></span><span class="line"><span class="cl">make install <span class="nv">PREFIX</span><span class="o">=</span><span class="nv">$HOME</span>/.local   <span class="c1"># → ~/.local/bin</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>The recommended Waybar config is a single module you scroll to cycle through vendors, with click to open the TUI:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-jsonc" data-lang="jsonc"><span class="line"><span class="cl"><span class="s2">&#34;custom/aibar&#34;</span><span class="err">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;exec&#34;</span><span class="p">:</span> <span class="s2">&#34;ai-usagebar --format &#39;{vendor_short} {session_pct}% · {session_reset}&#39;&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;return-type&#34;</span><span class="p">:</span> <span class="s2">&#34;json&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;interval&#34;</span><span class="p">:</span> <span class="mi">300</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;signal&#34;</span><span class="p">:</span> <span class="mi">13</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;tooltip&#34;</span><span class="p">:</span> <span class="kc">true</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;on-click&#34;</span><span class="p">:</span> <span class="s2">&#34;ai-usagebar-tui&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;on-scroll-up&#34;</span><span class="p">:</span>   <span class="s2">&#34;ai-usagebar --cycle-next&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;on-scroll-down&#34;</span><span class="p">:</span> <span class="s2">&#34;ai-usagebar --cycle-prev&#34;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>If you&rsquo;d rather see all four vendors at once, you can use one module per vendor. The <a href="https://github.com/akitaonrails/ai-usagebar"target="_blank" rel="noopener">README</a> has the full config detail, format placeholders, and the variations.</p>
<h2>Why I built it<span class="hx:absolute hx:-mt-20" id="why-i-built-it"></span>
    <a href="#why-i-built-it" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>This looked like a Saturday-night little project, so I just did it. And it was: porting claudebar to Rust and adding the extra vendors I wanted was painless. I came out of one night with a widget that does exactly what I needed and is more reliable (tested, modular) than the original shell script.</p>
<p>If you use other vendors I didn&rsquo;t cover, or you hit a bug, send an issue or pull request: <a href="https://github.com/akitaonrails/ai-usagebar"target="_blank" rel="noopener">github.com/akitaonrails/ai-usagebar</a>. It&rsquo;s MIT.</p>
]]></content:encoded><category>ai-usagebar</category><category>omarchy</category><category>developer-tools</category><category>llms</category></item><item><title>I Built a CLI to Check My GitHub Pending Stuff: ghpending</title><link>https://akitaonrails.github.io/en/2026/05/23/i-built-a-cli-to-check-my-github-pending-stuff-ghpending/</link><guid isPermaLink="true">https://akitaonrails.github.io/en/2026/05/23/i-built-a-cli-to-check-my-github-pending-stuff-ghpending/</guid><pubDate>Sat, 23 May 2026 22:00:00 -0300</pubDate><description>&lt;p&gt;After my &lt;a href="https://akitaonrails.github.io/en/2026/05/14/wrapping-up-my-ai-marathon-success-or-failure/"&gt;AI marathon&lt;/a&gt;, I&amp;rsquo;m sitting on dozens of public GitHub repos to look after. A bunch of them have contributors filing issues and sending pull requests. The problem is, opening a browser, walking into each repo, checking whether anything new is waiting, becomes a chore I end up dodging. And when I dodge it, I go weeks without responding to collaborators.&lt;/p&gt;
&lt;p&gt;I know there are plenty of tools that solve this. But I wanted something dead simple and fast to run in the terminal so I can see pending work across all my projects at once. So I built it: &lt;strong&gt;&lt;a href="https://github.com/akitaonrails/ghpending"target="_blank" rel="noopener"&gt;ghpending&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;</description><content:encoded><![CDATA[<p>After my <a href="/en/2026/05/14/wrapping-up-my-ai-marathon-success-or-failure/">AI marathon</a>, I&rsquo;m sitting on dozens of public GitHub repos to look after. A bunch of them have contributors filing issues and sending pull requests. The problem is, opening a browser, walking into each repo, checking whether anything new is waiting, becomes a chore I end up dodging. And when I dodge it, I go weeks without responding to collaborators.</p>
<p>I know there are plenty of tools that solve this. But I wanted something dead simple and fast to run in the terminal so I can see pending work across all my projects at once. So I built it: <strong><a href="https://github.com/akitaonrails/ghpending"target="_blank" rel="noopener">ghpending</a></strong>.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/05/23/ghpending/ghpending-screenshot.png" alt="ghpending output in the terminal: compact table listing each tracked repo with counts of open issues and pull requests, latest activity author, and how long ago."  loading="lazy" /></p>
<p>Runs on Linux and macOS. I tested on Linux (Arch + Omarchy) but haven&rsquo;t run it on macOS yet. If you try it there and hit a bug, file an issue at <a href="https://github.com/akitaonrails/ghpending/issues"target="_blank" rel="noopener">github.com/akitaonrails/ghpending/issues</a>.</p>
<h2>Install<span class="hx:absolute hx:-mt-20" id="install"></span>
    <a href="#install" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Three paths, pick whichever fits your setup.</p>
<p>Via Homebrew (macOS or Linux):</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sh" data-lang="sh"><span class="line"><span class="cl">brew tap akitaonrails/tap <span class="o">&amp;&amp;</span> brew install ghpending</span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Via Cargo:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sh" data-lang="sh"><span class="line"><span class="cl">cargo install ghpending</span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Via mise:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sh" data-lang="sh"><span class="line"><span class="cl">mise use -g github:akitaonrails/ghpending</span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<h2>Upgrading<span class="hx:absolute hx:-mt-20" id="upgrading"></span>
    <a href="#upgrading" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sh" data-lang="sh"><span class="line"><span class="cl"><span class="c1"># Homebrew</span>
</span></span><span class="line"><span class="cl">brew upgrade ghpending
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Cargo</span>
</span></span><span class="line"><span class="cl">cargo install ghpending --force
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># mise</span>
</span></span><span class="line"><span class="cl">mise upgrade ghpending
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># From source</span>
</span></span><span class="line"><span class="cl"><span class="nb">cd</span> ghpending <span class="o">&amp;&amp;</span> git pull <span class="o">&amp;&amp;</span> cargo install --path .</span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<h2>Usage<span class="hx:absolute hx:-mt-20" id="usage"></span>
    <a href="#usage" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Four commands. The normal flow is to run <code>ghpending add</code> once to set up which repos you want to track, then just <code>ghpending</code> whenever you want to see the digest.</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sh" data-lang="sh"><span class="line"><span class="cl">ghpending add    <span class="c1"># pick repos from a GitHub user or org to track</span>
</span></span><span class="line"><span class="cl">ghpending        <span class="c1"># print the digest of open issues and PRs</span>
</span></span><span class="line"><span class="cl">ghpending list   <span class="c1"># show tracked repos</span>
</span></span><span class="line"><span class="cl">ghpending rm     <span class="c1"># remove repos from tracking via interactive menu</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p><code>add</code> asks for a user or organization, lists their public repos, and lets you check off the ones you want to follow. The username gets saved, so re-running <code>add</code> skips that prompt.</p>
<p>The main command (<code>ghpending</code> with no args) fetches every tracked repo concurrently and prints the table with open issues and PRs.</p>
<h2>GitHub token (optional)<span class="hx:absolute hx:-mt-20" id="github-token-optional"></span>
    <a href="#github-token-optional" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>It works without auth, but GitHub caps anonymous traffic at 60 requests per hour. To raise that ceiling to 5,000 req/h, export a token:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sh" data-lang="sh"><span class="line"><span class="cl"><span class="nv">GITHUB_TOKEN</span><span class="o">=</span><span class="k">$(</span>gh auth token<span class="k">)</span> ghpending</span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>It&rsquo;s read silently at startup, no config needed.</p>
<h2>Where the config lives<span class="hx:absolute hx:-mt-20" id="where-the-config-lives"></span>
    <a href="#where-the-config-lives" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><ul>
<li>Linux: <code>~/.config/ghpending/config.toml</code></li>
<li>macOS: <code>~/Library/Application Support/ghpending/config.toml</code></li>
</ul>
<p>You can edit it directly if you want to reorder repos or change the <code>user</code>. Shape:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-toml" data-lang="toml"><span class="line"><span class="cl"><span class="nx">user</span> <span class="p">=</span> <span class="s2">&#34;akitaonrails&#34;</span>
</span></span><span class="line"><span class="cl"><span class="nx">repos</span> <span class="p">=</span> <span class="p">[</span><span class="s2">&#34;akitaonrails/ai-memory&#34;</span><span class="p">,</span> <span class="s2">&#34;akitaonrails/ai-jail&#34;</span><span class="p">]</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<h2>Why this CLI exists<span class="hx:absolute hx:-mt-20" id="why-this-cli-exists"></span>
    <a href="#why-this-cli-exists" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>The honest answer: tools I build for myself, I use. Tools written by other people always come with some friction (web login, a different architectural opinion, a feature I wanted missing or one I didn&rsquo;t want included). Since the goal was to reduce the friction of checking 30 repos a week, 200 lines of Rust on a Saturday afternoon beat learning a new stack.</p>
<p>Now I&rsquo;m hoping I can respond to contributors faster. If you find it useful, it&rsquo;s MIT licensed, PRs are welcome.</p>
]]></content:encoded><category>ghpending</category><category>automation</category><category>developer-tools</category><category>version-control</category></item><item><title>AI Agents: Installing LSPs for Crush</title><link>https://akitaonrails.github.io/en/2026/01/21/ai-agents-installing-lsps-for-crush/</link><guid isPermaLink="true">https://akitaonrails.github.io/en/2026/01/21/ai-agents-installing-lsps-for-crush/</guid><pubDate>Wed, 21 Jan 2026 13:14:07 -0300</pubDate><description>&lt;p&gt;This post is mostly for me to document things and not forget. As I said in the last few posts, I&amp;rsquo;ve been using &lt;a href="https://github.com/charmbracelet/crush"target="_blank" rel="noopener"&gt;Charm&amp;rsquo;s Crush&lt;/a&gt; as my favorite AI coding agent. Repeating myself: it doesn&amp;rsquo;t matter if you use Claude Code or OpenCode, they&amp;rsquo;re all equally good. My personal preference is still Crush because I think it looks nicer, that&amp;rsquo;s all.&lt;/p&gt;
&lt;p&gt;I still don&amp;rsquo;t fully understand how much of a difference it makes, but both OpenCode and Crush support Language Servers (LSPs), so I thought it&amp;rsquo;d be cool to have it configured. Here&amp;rsquo;s my &lt;code&gt;~/.config/crush/crush.json&lt;/code&gt;:&lt;/p&gt;</description><content:encoded><![CDATA[<p>This post is mostly for me to document things and not forget. As I said in the last few posts, I&rsquo;ve been using <a href="https://github.com/charmbracelet/crush"target="_blank" rel="noopener">Charm&rsquo;s Crush</a> as my favorite AI coding agent. Repeating myself: it doesn&rsquo;t matter if you use Claude Code or OpenCode, they&rsquo;re all equally good. My personal preference is still Crush because I think it looks nicer, that&rsquo;s all.</p>
<p>I still don&rsquo;t fully understand how much of a difference it makes, but both OpenCode and Crush support Language Servers (LSPs), so I thought it&rsquo;d be cool to have it configured. Here&rsquo;s my <code>~/.config/crush/crush.json</code>:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;$schema&#34;</span><span class="p">:</span> <span class="s2">&#34;https://charm.land/crush.json&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;default_provider&#34;</span><span class="p">:</span> <span class="s2">&#34;openrouter&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;providers&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;openrouter&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;api_key&#34;</span><span class="p">:</span> <span class="s2">&#34;sk-...&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;lmstudio&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;name&#34;</span><span class="p">:</span> <span class="s2">&#34;LM Studio&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;base_url&#34;</span><span class="p">:</span> <span class="s2">&#34;http://localhost:1234/v1/&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;type&#34;</span><span class="p">:</span> <span class="s2">&#34;openai&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;models&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">        <span class="p">{</span>
</span></span><span class="line"><span class="cl">          <span class="nt">&#34;name&#34;</span><span class="p">:</span> <span class="s2">&#34;gpt-oss-120b&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">          <span class="nt">&#34;id&#34;</span><span class="p">:</span> <span class="s2">&#34;gpt-oss:120b&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">          <span class="nt">&#34;context_window&#34;</span><span class="p">:</span> <span class="mi">100000</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">          <span class="nt">&#34;default_max_tokens&#34;</span><span class="p">:</span> <span class="mi">-1</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">          <span class="nt">&#34;supports_tools&#34;</span><span class="p">:</span> <span class="kc">true</span>
</span></span><span class="line"><span class="cl">        <span class="p">},</span>
</span></span><span class="line"><span class="cl">        <span class="p">{</span>
</span></span><span class="line"><span class="cl">          <span class="nt">&#34;name&#34;</span><span class="p">:</span> <span class="s2">&#34;gpt-oss-20b&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">          <span class="nt">&#34;id&#34;</span><span class="p">:</span> <span class="s2">&#34;gpt-oss:20b&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">          <span class="nt">&#34;context_window&#34;</span><span class="p">:</span> <span class="mi">130000</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">          <span class="nt">&#34;default_max_tokens&#34;</span><span class="p">:</span> <span class="mi">-1</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">          <span class="nt">&#34;supports_tools&#34;</span><span class="p">:</span> <span class="kc">true</span>
</span></span><span class="line"><span class="cl">        <span class="p">},</span>
</span></span><span class="line"><span class="cl">        <span class="p">{</span>
</span></span><span class="line"><span class="cl">          <span class="nt">&#34;name&#34;</span><span class="p">:</span> <span class="s2">&#34;zai-org/glm-4.6v-flash&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">          <span class="nt">&#34;id&#34;</span><span class="p">:</span> <span class="s2">&#34;glm-4.6v-flash&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">          <span class="nt">&#34;context_window&#34;</span><span class="p">:</span> <span class="mi">130000</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">          <span class="nt">&#34;default_max_tokens&#34;</span><span class="p">:</span> <span class="mi">-1</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">          <span class="nt">&#34;supports_tools&#34;</span><span class="p">:</span> <span class="kc">true</span>
</span></span><span class="line"><span class="cl">        <span class="p">},</span>
</span></span><span class="line"><span class="cl">        <span class="p">{</span>
</span></span><span class="line"><span class="cl">          <span class="nt">&#34;name&#34;</span><span class="p">:</span> <span class="s2">&#34;deepseek-coder-v2-lite-instruct&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">          <span class="nt">&#34;id&#34;</span><span class="p">:</span> <span class="s2">&#34;deepseek-coder-v2-lite-instruct&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">          <span class="nt">&#34;context_window&#34;</span><span class="p">:</span> <span class="mi">64000</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">          <span class="nt">&#34;default_max_tokens&#34;</span><span class="p">:</span> <span class="mi">-1</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">          <span class="nt">&#34;supports_tools&#34;</span><span class="p">:</span> <span class="kc">true</span>
</span></span><span class="line"><span class="cl">        <span class="p">},</span>
</span></span><span class="line"><span class="cl">        <span class="p">{</span>
</span></span><span class="line"><span class="cl">          <span class="nt">&#34;id&#34;</span><span class="p">:</span> <span class="s2">&#34;qwen/qwen3-coder-30b&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">          <span class="nt">&#34;name&#34;</span><span class="p">:</span> <span class="s2">&#34;qwen3-coder-30b&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">          <span class="nt">&#34;context_window&#34;</span><span class="p">:</span> <span class="mi">120000</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">          <span class="nt">&#34;default_max_tokens&#34;</span><span class="p">:</span> <span class="mi">-1</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">          <span class="nt">&#34;supports_tools&#34;</span><span class="p">:</span> <span class="kc">true</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">      <span class="p">]</span>
</span></span><span class="line"><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;ollama&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;type&#34;</span><span class="p">:</span> <span class="s2">&#34;openai-compat&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;base_url&#34;</span><span class="p">:</span> <span class="s2">&#34;http://127.0.0.1:11434/v1&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;api_key&#34;</span><span class="p">:</span> <span class="s2">&#34;ollama&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;models&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">        <span class="p">{</span>
</span></span><span class="line"><span class="cl">          <span class="nt">&#34;name&#34;</span><span class="p">:</span> <span class="s2">&#34;glm-4.7-flash&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">          <span class="nt">&#34;id&#34;</span><span class="p">:</span> <span class="s2">&#34;glm-4.7-flash&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">          <span class="nt">&#34;context_window&#34;</span><span class="p">:</span> <span class="mi">65536</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">          <span class="nt">&#34;default_max_tokens&#34;</span><span class="p">:</span> <span class="mi">-1</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">          <span class="nt">&#34;supports_tools&#34;</span><span class="p">:</span> <span class="kc">true</span>
</span></span><span class="line"><span class="cl">        <span class="p">},</span>
</span></span><span class="line"><span class="cl">        <span class="p">{</span>
</span></span><span class="line"><span class="cl">          <span class="nt">&#34;name&#34;</span><span class="p">:</span> <span class="s2">&#34;gpt-oss-20b&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">          <span class="nt">&#34;id&#34;</span><span class="p">:</span> <span class="s2">&#34;gpt-oss:20b&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">          <span class="nt">&#34;context_window&#34;</span><span class="p">:</span> <span class="mi">64000</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">          <span class="nt">&#34;default_max_tokens&#34;</span><span class="p">:</span> <span class="mi">-1</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">          <span class="nt">&#34;supports_tools&#34;</span><span class="p">:</span> <span class="kc">true</span>
</span></span><span class="line"><span class="cl">        <span class="p">},</span>
</span></span><span class="line"><span class="cl">        <span class="p">{</span>
</span></span><span class="line"><span class="cl">          <span class="nt">&#34;id&#34;</span><span class="p">:</span> <span class="s2">&#34;qwen3-nuclear&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">          <span class="nt">&#34;name&#34;</span><span class="p">:</span> <span class="s2">&#34;qwen3-nuclear&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">          <span class="nt">&#34;context_window&#34;</span><span class="p">:</span> <span class="mi">120000</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">          <span class="nt">&#34;default_max_tokens&#34;</span><span class="p">:</span> <span class="mi">-1</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">          <span class="nt">&#34;supports_tools&#34;</span><span class="p">:</span> <span class="kc">true</span>
</span></span><span class="line"><span class="cl">        <span class="p">},</span>
</span></span><span class="line"><span class="cl">        <span class="p">{</span>
</span></span><span class="line"><span class="cl">          <span class="nt">&#34;id&#34;</span><span class="p">:</span> <span class="s2">&#34;qwen3-coder:30b&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">          <span class="nt">&#34;name&#34;</span><span class="p">:</span> <span class="s2">&#34;qwen3-coder:30b&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">          <span class="nt">&#34;context_window&#34;</span><span class="p">:</span> <span class="mi">120000</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">          <span class="nt">&#34;default_max_tokens&#34;</span><span class="p">:</span> <span class="mi">-1</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">          <span class="nt">&#34;supports_tools&#34;</span><span class="p">:</span> <span class="kc">true</span>
</span></span><span class="line"><span class="cl">        <span class="p">},</span>
</span></span><span class="line"><span class="cl">        <span class="p">{</span>
</span></span><span class="line"><span class="cl">          <span class="nt">&#34;id&#34;</span><span class="p">:</span> <span class="s2">&#34;qwen2.5-coder:32b&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">          <span class="nt">&#34;name&#34;</span><span class="p">:</span> <span class="s2">&#34;qwen2.5-coder:32b&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">          <span class="nt">&#34;context_window&#34;</span><span class="p">:</span> <span class="mi">32768</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">          <span class="nt">&#34;default_max_tokens&#34;</span><span class="p">:</span> <span class="mi">-1</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">          <span class="nt">&#34;supports_tools&#34;</span><span class="p">:</span> <span class="kc">true</span>
</span></span><span class="line"><span class="cl">        <span class="p">},</span>
</span></span><span class="line"><span class="cl">        <span class="p">{</span>
</span></span><span class="line"><span class="cl">          <span class="nt">&#34;id&#34;</span><span class="p">:</span> <span class="s2">&#34;deepseek-coder-v2:16b&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">          <span class="nt">&#34;name&#34;</span><span class="p">:</span> <span class="s2">&#34;deepseek-coder-v2:16b&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">          <span class="nt">&#34;context_window&#34;</span><span class="p">:</span> <span class="mi">128000</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">          <span class="nt">&#34;default_max_tokens&#34;</span><span class="p">:</span> <span class="mi">-1</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">          <span class="nt">&#34;supports_tools&#34;</span><span class="p">:</span> <span class="kc">true</span>
</span></span><span class="line"><span class="cl">        <span class="p">},</span>
</span></span><span class="line"><span class="cl">        <span class="p">{</span>
</span></span><span class="line"><span class="cl">          <span class="nt">&#34;id&#34;</span><span class="p">:</span> <span class="s2">&#34;glm-4.7:cloud&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">          <span class="nt">&#34;name&#34;</span><span class="p">:</span> <span class="s2">&#34;glm-4.7:cloud&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">          <span class="nt">&#34;context_window&#34;</span><span class="p">:</span> <span class="mi">128000</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">          <span class="nt">&#34;default_max_tokens&#34;</span><span class="p">:</span> <span class="mi">-1</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">          <span class="nt">&#34;supports_tools&#34;</span><span class="p">:</span> <span class="kc">true</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">      <span class="p">]</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">  <span class="p">},</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;lsp&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;gopls&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;command&#34;</span><span class="p">:</span> <span class="s2">&#34;gopls&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;rust-analyzer&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;command&#34;</span><span class="p">:</span> <span class="s2">&#34;rust-analyzer&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;ruby-lsp&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;command&#34;</span><span class="p">:</span> <span class="s2">&#34;ruby-lsp&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;solargraph&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;command&#34;</span><span class="p">:</span> <span class="s2">&#34;solargraph&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;args&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;stdio&#34;</span>
</span></span><span class="line"><span class="cl">      <span class="p">]</span>
</span></span><span class="line"><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;pylsp&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;command&#34;</span><span class="p">:</span> <span class="s2">&#34;pylsp&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;pyright&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;command&#34;</span><span class="p">:</span> <span class="s2">&#34;pyright-langserver&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;args&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;--stdio&#34;</span>
</span></span><span class="line"><span class="cl">      <span class="p">]</span>
</span></span><span class="line"><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;elixir-ls&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;command&#34;</span><span class="p">:</span> <span class="s2">&#34;elixir-ls&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;docker-langserver&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;command&#34;</span><span class="p">:</span> <span class="s2">&#34;docker-langserver&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;args&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;--stdio&#34;</span>
</span></span><span class="line"><span class="cl">      <span class="p">],</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;languages&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;dockerfile&#34;</span>
</span></span><span class="line"><span class="cl">      <span class="p">]</span>
</span></span><span class="line"><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;bash-language-server&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;command&#34;</span><span class="p">:</span> <span class="s2">&#34;bash-language-server&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;args&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;start&#34;</span>
</span></span><span class="line"><span class="cl">      <span class="p">]</span>
</span></span><span class="line"><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;marksman&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;command&#34;</span><span class="p">:</span> <span class="s2">&#34;marksman&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;args&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;server&#34;</span>
</span></span><span class="line"><span class="cl">      <span class="p">]</span>
</span></span><span class="line"><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;typescript-language-server&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;command&#34;</span><span class="p">:</span> <span class="s2">&#34;typescript-language-server&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;args&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;--stdio&#34;</span>
</span></span><span class="line"><span class="cl">      <span class="p">]</span>
</span></span><span class="line"><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;vscode-html-language-server&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;command&#34;</span><span class="p">:</span> <span class="s2">&#34;vscode-html-language-server&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;args&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;--stdio&#34;</span>
</span></span><span class="line"><span class="cl">      <span class="p">]</span>
</span></span><span class="line"><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;vscode-css-language-server&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;command&#34;</span><span class="p">:</span> <span class="s2">&#34;vscode-css-language-server&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;args&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;--stdio&#34;</span>
</span></span><span class="line"><span class="cl">      <span class="p">]</span>
</span></span><span class="line"><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;vscode-json-language-server&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;command&#34;</span><span class="p">:</span> <span class="s2">&#34;vscode-json-language-server&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;args&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;--stdio&#34;</span>
</span></span><span class="line"><span class="cl">      <span class="p">]</span>
</span></span><span class="line"><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;yaml-language-server&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;command&#34;</span><span class="p">:</span> <span class="s2">&#34;yaml-language-server&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;args&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;--stdio&#34;</span>
</span></span><span class="line"><span class="cl">      <span class="p">]</span>
</span></span><span class="line"><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;taplo&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;command&#34;</span><span class="p">:</span> <span class="s2">&#34;taplo&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;args&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;lsp&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;stdio&#34;</span>
</span></span><span class="line"><span class="cl">      <span class="p">]</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">  <span class="p">},</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;mcp&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;blender&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;type&#34;</span><span class="p">:</span> <span class="s2">&#34;stdio&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;command&#34;</span><span class="p">:</span> <span class="s2">&#34;uvx&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;args&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;blender-mcp&#34;</span>
</span></span><span class="line"><span class="cl">      <span class="p">]</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Note that I primarily use Claude Opus 4.5 via OpenRouter and I have LM Studio and Ollama configured as providers for testing other open source models.</p>
<p>I also use <a href="/en/2025/09/07/omarchy-2-0-mise-for-organizing-dev-environments/">Mise</a> to organize the programming languages I use.</p>
<p>But now you need to install the LSPs for each language. I don&rsquo;t know of a better way to manage this the same way Mason does in Neovim. So I made a script to install everything for me (on my Arch Linux). For that I created this script <code>~/.local/bin/install-lsps.sh</code>:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="cp">#!/usr/bin/env bash
</span></span></span><span class="line"><span class="cl"><span class="nb">set</span> -euo pipefail
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># LSP Installer for Arch Linux with Mise</span>
</span></span><span class="line"><span class="cl"><span class="c1"># Installs major LSPs using native package managers or yay</span>
</span></span><span class="line"><span class="cl"><span class="c1"># Only installs LSPs for languages that are already installed</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nv">GREEN</span><span class="o">=</span><span class="s1">&#39;\033[0;32m&#39;</span>
</span></span><span class="line"><span class="cl"><span class="nv">BLUE</span><span class="o">=</span><span class="s1">&#39;\033[0;34m&#39;</span>
</span></span><span class="line"><span class="cl"><span class="nv">YELLOW</span><span class="o">=</span><span class="s1">&#39;\033[1;33m&#39;</span>
</span></span><span class="line"><span class="cl"><span class="nv">RED</span><span class="o">=</span><span class="s1">&#39;\033[0;31m&#39;</span>
</span></span><span class="line"><span class="cl"><span class="nv">NC</span><span class="o">=</span><span class="s1">&#39;\033[0m&#39;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">info<span class="o">()</span> <span class="o">{</span> <span class="nb">echo</span> -e <span class="s2">&#34;</span><span class="si">${</span><span class="nv">BLUE</span><span class="si">}</span><span class="s2">[INFO]</span><span class="si">${</span><span class="nv">NC</span><span class="si">}</span><span class="s2"> </span><span class="nv">$1</span><span class="s2">&#34;</span><span class="p">;</span> <span class="o">}</span>
</span></span><span class="line"><span class="cl">success<span class="o">()</span> <span class="o">{</span> <span class="nb">echo</span> -e <span class="s2">&#34;</span><span class="si">${</span><span class="nv">GREEN</span><span class="si">}</span><span class="s2">[OK]</span><span class="si">${</span><span class="nv">NC</span><span class="si">}</span><span class="s2"> </span><span class="nv">$1</span><span class="s2">&#34;</span><span class="p">;</span> <span class="o">}</span>
</span></span><span class="line"><span class="cl">warn<span class="o">()</span> <span class="o">{</span> <span class="nb">echo</span> -e <span class="s2">&#34;</span><span class="si">${</span><span class="nv">YELLOW</span><span class="si">}</span><span class="s2">[SKIP]</span><span class="si">${</span><span class="nv">NC</span><span class="si">}</span><span class="s2"> </span><span class="nv">$1</span><span class="s2">&#34;</span><span class="p">;</span> <span class="o">}</span>
</span></span><span class="line"><span class="cl">skip_lang<span class="o">()</span> <span class="o">{</span> <span class="nb">echo</span> -e <span class="s2">&#34;</span><span class="si">${</span><span class="nv">RED</span><span class="si">}</span><span class="s2">[LANG]</span><span class="si">${</span><span class="nv">NC</span><span class="si">}</span><span class="s2"> </span><span class="nv">$1</span><span class="s2"> not installed, skipping LSPs&#34;</span><span class="p">;</span> <span class="o">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">command_exists<span class="o">()</span> <span class="o">{</span> <span class="nb">command</span> -v <span class="s2">&#34;</span><span class="nv">$1</span><span class="s2">&#34;</span> <span class="p">&amp;</span>&gt;/dev/null<span class="p">;</span> <span class="o">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># ─────────────────────────────────────────────────────────────</span>
</span></span><span class="line"><span class="cl"><span class="c1"># Language detection helpers</span>
</span></span><span class="line"><span class="cl"><span class="c1"># ─────────────────────────────────────────────────────────────</span>
</span></span><span class="line"><span class="cl">has_c<span class="o">()</span>       <span class="o">{</span> command_exists gcc <span class="o">||</span> command_exists clang<span class="p">;</span> <span class="o">}</span>
</span></span><span class="line"><span class="cl">has_rust<span class="o">()</span>    <span class="o">{</span> command_exists rustc <span class="o">||</span> command_exists cargo<span class="p">;</span> <span class="o">}</span>
</span></span><span class="line"><span class="cl">has_go<span class="o">()</span>      <span class="o">{</span> command_exists go<span class="p">;</span> <span class="o">}</span>
</span></span><span class="line"><span class="cl">has_python<span class="o">()</span>  <span class="o">{</span> command_exists python <span class="o">||</span> command_exists python3<span class="p">;</span> <span class="o">}</span>
</span></span><span class="line"><span class="cl">has_node<span class="o">()</span>    <span class="o">{</span> command_exists node <span class="o">||</span> command_exists npm<span class="p">;</span> <span class="o">}</span>
</span></span><span class="line"><span class="cl">has_java<span class="o">()</span>    <span class="o">{</span> command_exists java <span class="o">||</span> command_exists javac<span class="p">;</span> <span class="o">}</span>
</span></span><span class="line"><span class="cl">has_kotlin<span class="o">()</span>  <span class="o">{</span> command_exists kotlin <span class="o">||</span> command_exists kotlinc<span class="p">;</span> <span class="o">}</span>
</span></span><span class="line"><span class="cl">has_ruby<span class="o">()</span>    <span class="o">{</span> command_exists ruby<span class="p">;</span> <span class="o">}</span>
</span></span><span class="line"><span class="cl">has_php<span class="o">()</span>     <span class="o">{</span> command_exists php<span class="p">;</span> <span class="o">}</span>
</span></span><span class="line"><span class="cl">has_lua<span class="o">()</span>     <span class="o">{</span> command_exists lua <span class="o">||</span> command_exists luajit<span class="p">;</span> <span class="o">}</span>
</span></span><span class="line"><span class="cl">has_zig<span class="o">()</span>     <span class="o">{</span> command_exists zig<span class="p">;</span> <span class="o">}</span>
</span></span><span class="line"><span class="cl">has_haskell<span class="o">()</span> <span class="o">{</span> command_exists ghc <span class="o">||</span> command_exists stack <span class="o">||</span> command_exists cabal<span class="p">;</span> <span class="o">}</span>
</span></span><span class="line"><span class="cl">has_elixir<span class="o">()</span>  <span class="o">{</span> command_exists elixir <span class="o">||</span> command_exists iex<span class="p">;</span> <span class="o">}</span>
</span></span><span class="line"><span class="cl">has_scala<span class="o">()</span>   <span class="o">{</span> command_exists scala <span class="o">||</span> command_exists sbt<span class="p">;</span> <span class="o">}</span>
</span></span><span class="line"><span class="cl">has_dotnet<span class="o">()</span>  <span class="o">{</span> command_exists dotnet<span class="p">;</span> <span class="o">}</span>
</span></span><span class="line"><span class="cl">has_ocaml<span class="o">()</span>   <span class="o">{</span> command_exists ocaml <span class="o">||</span> command_exists opam<span class="p">;</span> <span class="o">}</span>
</span></span><span class="line"><span class="cl">has_clojure<span class="o">()</span> <span class="o">{</span> command_exists clojure <span class="o">||</span> command_exists clj <span class="o">||</span> command_exists lein<span class="p">;</span> <span class="o">}</span>
</span></span><span class="line"><span class="cl">has_nix<span class="o">()</span>     <span class="o">{</span> command_exists nix<span class="p">;</span> <span class="o">}</span>
</span></span><span class="line"><span class="cl">has_terraform<span class="o">()</span> <span class="o">{</span> command_exists terraform <span class="o">||</span> command_exists tofu<span class="p">;</span> <span class="o">}</span>
</span></span><span class="line"><span class="cl">has_latex<span class="o">()</span>   <span class="o">{</span> command_exists latex <span class="o">||</span> command_exists pdflatex <span class="o">||</span> command_exists xelatex<span class="p">;</span> <span class="o">}</span>
</span></span><span class="line"><span class="cl">has_docker<span class="o">()</span>  <span class="o">{</span> command_exists docker <span class="o">||</span> command_exists podman<span class="p">;</span> <span class="o">}</span>
</span></span><span class="line"><span class="cl">has_ansible<span class="o">()</span> <span class="o">{</span> command_exists ansible<span class="p">;</span> <span class="o">}</span>
</span></span><span class="line"><span class="cl">has_sql<span class="o">()</span>     <span class="o">{</span> command_exists psql <span class="o">||</span> command_exists mysql <span class="o">||</span> command_exists sqlite3<span class="p">;</span> <span class="o">}</span>
</span></span><span class="line"><span class="cl">has_bash<span class="o">()</span>    <span class="o">{</span> command_exists bash<span class="p">;</span> <span class="o">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># ─────────────────────────────────────────────────────────────</span>
</span></span><span class="line"><span class="cl"><span class="c1"># Package installation helpers</span>
</span></span><span class="line"><span class="cl"><span class="c1"># ─────────────────────────────────────────────────────────────</span>
</span></span><span class="line"><span class="cl">install_pacman<span class="o">()</span> <span class="o">{</span>
</span></span><span class="line"><span class="cl">    <span class="nb">local</span> <span class="nv">pkg</span><span class="o">=</span><span class="s2">&#34;</span><span class="nv">$1</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> pacman -Qi <span class="s2">&#34;</span><span class="nv">$pkg</span><span class="s2">&#34;</span> <span class="p">&amp;</span>&gt;/dev/null<span class="p">;</span> <span class="k">then</span>
</span></span><span class="line"><span class="cl">        warn <span class="s2">&#34;</span><span class="nv">$pkg</span><span class="s2"> already installed&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="k">else</span>
</span></span><span class="line"><span class="cl">        sudo pacman -S --noconfirm --needed <span class="s2">&#34;</span><span class="nv">$pkg</span><span class="s2">&#34;</span> <span class="o">&amp;&amp;</span> success <span class="s2">&#34;</span><span class="nv">$pkg</span><span class="s2">&#34;</span> <span class="o">||</span> warn <span class="s2">&#34;Failed: </span><span class="nv">$pkg</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="k">fi</span>
</span></span><span class="line"><span class="cl"><span class="o">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">install_yay<span class="o">()</span> <span class="o">{</span>
</span></span><span class="line"><span class="cl">    <span class="nb">local</span> <span class="nv">pkg</span><span class="o">=</span><span class="s2">&#34;</span><span class="nv">$1</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> ! command_exists yay<span class="p">;</span> <span class="k">then</span>
</span></span><span class="line"><span class="cl">        warn <span class="s2">&#34;yay not found, skipping </span><span class="nv">$pkg</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span>
</span></span><span class="line"><span class="cl">    <span class="k">fi</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> yay -Qi <span class="s2">&#34;</span><span class="nv">$pkg</span><span class="s2">&#34;</span> <span class="p">&amp;</span>&gt;/dev/null<span class="p">;</span> <span class="k">then</span>
</span></span><span class="line"><span class="cl">        warn <span class="s2">&#34;</span><span class="nv">$pkg</span><span class="s2"> already installed&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="k">else</span>
</span></span><span class="line"><span class="cl">        yay -S --noconfirm --needed <span class="s2">&#34;</span><span class="nv">$pkg</span><span class="s2">&#34;</span> <span class="o">&amp;&amp;</span> success <span class="s2">&#34;</span><span class="nv">$pkg</span><span class="s2">&#34;</span> <span class="o">||</span> warn <span class="s2">&#34;Failed: </span><span class="nv">$pkg</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="k">fi</span>
</span></span><span class="line"><span class="cl"><span class="o">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">install_npm<span class="o">()</span> <span class="o">{</span>
</span></span><span class="line"><span class="cl">    <span class="nb">local</span> <span class="nv">pkg</span><span class="o">=</span><span class="s2">&#34;</span><span class="nv">$1</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> npm list -g <span class="s2">&#34;</span><span class="nv">$pkg</span><span class="s2">&#34;</span> <span class="p">&amp;</span>&gt;/dev/null 2&gt;<span class="p">&amp;</span>1<span class="p">;</span> <span class="k">then</span>
</span></span><span class="line"><span class="cl">        warn <span class="s2">&#34;</span><span class="nv">$pkg</span><span class="s2"> already installed&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="k">else</span>
</span></span><span class="line"><span class="cl">        npm install -g <span class="s2">&#34;</span><span class="nv">$pkg</span><span class="s2">&#34;</span> <span class="o">&amp;&amp;</span> success <span class="s2">&#34;</span><span class="nv">$pkg</span><span class="s2">&#34;</span> <span class="o">||</span> warn <span class="s2">&#34;Failed: </span><span class="nv">$pkg</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="k">fi</span>
</span></span><span class="line"><span class="cl"><span class="o">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">install_pipx<span class="o">()</span> <span class="o">{</span>
</span></span><span class="line"><span class="cl">    <span class="nb">local</span> <span class="nv">pkg</span><span class="o">=</span><span class="s2">&#34;</span><span class="nv">$1</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> ! command_exists pipx<span class="p">;</span> <span class="k">then</span>
</span></span><span class="line"><span class="cl">        pip install --user pipx 2&gt;/dev/null <span class="o">||</span> <span class="o">{</span>
</span></span><span class="line"><span class="cl">            pip install --user <span class="s2">&#34;</span><span class="nv">$pkg</span><span class="s2">&#34;</span> <span class="o">&amp;&amp;</span> success <span class="s2">&#34;</span><span class="nv">$pkg</span><span class="s2">&#34;</span> <span class="o">||</span> warn <span class="s2">&#34;Failed: </span><span class="nv">$pkg</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl">            <span class="k">return</span>
</span></span><span class="line"><span class="cl">        <span class="o">}</span>
</span></span><span class="line"><span class="cl">    <span class="k">fi</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> pipx list 2&gt;/dev/null <span class="p">|</span> grep -q <span class="s2">&#34;</span><span class="nv">$pkg</span><span class="s2">&#34;</span><span class="p">;</span> <span class="k">then</span>
</span></span><span class="line"><span class="cl">        warn <span class="s2">&#34;</span><span class="nv">$pkg</span><span class="s2"> already installed&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="k">else</span>
</span></span><span class="line"><span class="cl">        pipx install <span class="s2">&#34;</span><span class="nv">$pkg</span><span class="s2">&#34;</span> <span class="o">&amp;&amp;</span> success <span class="s2">&#34;</span><span class="nv">$pkg</span><span class="s2">&#34;</span> <span class="o">||</span> warn <span class="s2">&#34;Failed: </span><span class="nv">$pkg</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="k">fi</span>
</span></span><span class="line"><span class="cl"><span class="o">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">install_go<span class="o">()</span> <span class="o">{</span>
</span></span><span class="line"><span class="cl">    <span class="nb">local</span> <span class="nv">pkg</span><span class="o">=</span><span class="s2">&#34;</span><span class="nv">$1</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="nb">local</span> <span class="nv">name</span><span class="o">=</span><span class="s2">&#34;</span><span class="si">${</span><span class="nv">pkg</span><span class="p">##*/</span><span class="si">}</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="nv">name</span><span class="o">=</span><span class="s2">&#34;</span><span class="si">${</span><span class="nv">name</span><span class="p">%%@*</span><span class="si">}</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl">    
</span></span><span class="line"><span class="cl">    <span class="c1"># Check if binary already exists in GOPATH/bin</span>
</span></span><span class="line"><span class="cl">    <span class="nb">local</span> <span class="nv">gobin</span><span class="o">=</span><span class="s2">&#34;</span><span class="si">${</span><span class="nv">GOBIN</span><span class="k">:-</span><span class="si">${</span><span class="nv">GOPATH</span><span class="k">:-</span><span class="nv">$HOME</span><span class="p">/go</span><span class="si">}</span><span class="p">/bin</span><span class="si">}</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="o">[[</span> -x <span class="s2">&#34;</span><span class="nv">$gobin</span><span class="s2">/</span><span class="nv">$name</span><span class="s2">&#34;</span> <span class="o">]]</span><span class="p">;</span> <span class="k">then</span>
</span></span><span class="line"><span class="cl">        warn <span class="s2">&#34;</span><span class="nv">$name</span><span class="s2"> already installed&#34;</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span>
</span></span><span class="line"><span class="cl">    <span class="k">fi</span>
</span></span><span class="line"><span class="cl">    
</span></span><span class="line"><span class="cl">    go install <span class="s2">&#34;</span><span class="nv">$pkg</span><span class="s2">&#34;</span> <span class="o">&amp;&amp;</span> success <span class="s2">&#34;</span><span class="nv">$name</span><span class="s2">&#34;</span> <span class="o">||</span> warn <span class="s2">&#34;Failed: </span><span class="nv">$name</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl"><span class="o">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">install_gem<span class="o">()</span> <span class="o">{</span>
</span></span><span class="line"><span class="cl">    <span class="nb">local</span> <span class="nv">pkg</span><span class="o">=</span><span class="s2">&#34;</span><span class="nv">$1</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> gem list -i <span class="s2">&#34;^</span><span class="si">${</span><span class="nv">pkg</span><span class="si">}</span>$<span class="s2">&#34;</span> <span class="p">&amp;</span>&gt;/dev/null<span class="p">;</span> <span class="k">then</span>
</span></span><span class="line"><span class="cl">        warn <span class="s2">&#34;</span><span class="nv">$pkg</span><span class="s2"> already installed&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="k">else</span>
</span></span><span class="line"><span class="cl">        gem install <span class="s2">&#34;</span><span class="nv">$pkg</span><span class="s2">&#34;</span> <span class="o">&amp;&amp;</span> success <span class="s2">&#34;</span><span class="nv">$pkg</span><span class="s2">&#34;</span> <span class="o">||</span> warn <span class="s2">&#34;Failed: </span><span class="nv">$pkg</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="k">fi</span>
</span></span><span class="line"><span class="cl"><span class="o">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># ─────────────────────────────────────────────────────────────</span>
</span></span><span class="line"><span class="cl"><span class="c1"># C/C++ LSPs</span>
</span></span><span class="line"><span class="cl"><span class="c1"># ─────────────────────────────────────────────────────────────</span>
</span></span><span class="line"><span class="cl">install_c_lsps<span class="o">()</span> <span class="o">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> ! has_c<span class="p">;</span> <span class="k">then</span>
</span></span><span class="line"><span class="cl">        skip_lang <span class="s2">&#34;C/C++ (gcc/clang)&#34;</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span>
</span></span><span class="line"><span class="cl">    <span class="k">fi</span>
</span></span><span class="line"><span class="cl">    info <span class="s2">&#34;Installing C/C++ LSPs...&#34;</span>
</span></span><span class="line"><span class="cl">    install_pacman clang  <span class="c1"># includes clangd</span>
</span></span><span class="line"><span class="cl"><span class="o">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># ─────────────────────────────────────────────────────────────</span>
</span></span><span class="line"><span class="cl"><span class="c1"># Rust LSPs</span>
</span></span><span class="line"><span class="cl"><span class="c1"># ─────────────────────────────────────────────────────────────</span>
</span></span><span class="line"><span class="cl">install_rust_lsps<span class="o">()</span> <span class="o">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> ! has_rust<span class="p">;</span> <span class="k">then</span>
</span></span><span class="line"><span class="cl">        skip_lang <span class="s2">&#34;Rust&#34;</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span>
</span></span><span class="line"><span class="cl">    <span class="k">fi</span>
</span></span><span class="line"><span class="cl">    info <span class="s2">&#34;Installing Rust LSPs...&#34;</span>
</span></span><span class="line"><span class="cl">    
</span></span><span class="line"><span class="cl">    <span class="k">if</span> command_exists rustup<span class="p">;</span> <span class="k">then</span>
</span></span><span class="line"><span class="cl">        rustup component add rust-analyzer 2&gt;/dev/null <span class="o">&amp;&amp;</span> success <span class="s2">&#34;rust-analyzer (rustup)&#34;</span> <span class="o">||</span> install_pacman rust-analyzer
</span></span><span class="line"><span class="cl">    <span class="k">else</span>
</span></span><span class="line"><span class="cl">        install_pacman rust-analyzer
</span></span><span class="line"><span class="cl">    <span class="k">fi</span>
</span></span><span class="line"><span class="cl"><span class="o">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># ─────────────────────────────────────────────────────────────</span>
</span></span><span class="line"><span class="cl"><span class="c1"># Go LSPs</span>
</span></span><span class="line"><span class="cl"><span class="c1"># ─────────────────────────────────────────────────────────────</span>
</span></span><span class="line"><span class="cl">install_go_lsps<span class="o">()</span> <span class="o">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> ! has_go<span class="p">;</span> <span class="k">then</span>
</span></span><span class="line"><span class="cl">        skip_lang <span class="s2">&#34;Go&#34;</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span>
</span></span><span class="line"><span class="cl">    <span class="k">fi</span>
</span></span><span class="line"><span class="cl">    info <span class="s2">&#34;Installing Go LSPs...&#34;</span>
</span></span><span class="line"><span class="cl">    
</span></span><span class="line"><span class="cl">    install_go golang.org/x/tools/gopls@latest
</span></span><span class="line"><span class="cl">    install_go github.com/go-delve/delve/cmd/dlv@latest
</span></span><span class="line"><span class="cl">    install_go github.com/nametake/golangci-lint-langserver@latest
</span></span><span class="line"><span class="cl"><span class="o">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># ─────────────────────────────────────────────────────────────</span>
</span></span><span class="line"><span class="cl"><span class="c1"># Python LSPs</span>
</span></span><span class="line"><span class="cl"><span class="c1"># ─────────────────────────────────────────────────────────────</span>
</span></span><span class="line"><span class="cl">install_python_lsps<span class="o">()</span> <span class="o">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> ! has_python<span class="p">;</span> <span class="k">then</span>
</span></span><span class="line"><span class="cl">        skip_lang <span class="s2">&#34;Python&#34;</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span>
</span></span><span class="line"><span class="cl">    <span class="k">fi</span>
</span></span><span class="line"><span class="cl">    info <span class="s2">&#34;Installing Python LSPs...&#34;</span>
</span></span><span class="line"><span class="cl">    
</span></span><span class="line"><span class="cl">    <span class="c1"># Prefer npm pyright (faster updates) if node available</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> has_node<span class="p">;</span> <span class="k">then</span>
</span></span><span class="line"><span class="cl">        install_npm pyright
</span></span><span class="line"><span class="cl">    <span class="k">else</span>
</span></span><span class="line"><span class="cl">        install_pipx pyright
</span></span><span class="line"><span class="cl">    <span class="k">fi</span>
</span></span><span class="line"><span class="cl">    
</span></span><span class="line"><span class="cl">    install_pipx python-lsp-server
</span></span><span class="line"><span class="cl">    install_pipx ruff-lsp
</span></span><span class="line"><span class="cl"><span class="o">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># ─────────────────────────────────────────────────────────────</span>
</span></span><span class="line"><span class="cl"><span class="c1"># Node.js/TypeScript LSPs</span>
</span></span><span class="line"><span class="cl"><span class="c1"># ─────────────────────────────────────────────────────────────</span>
</span></span><span class="line"><span class="cl">install_node_lsps<span class="o">()</span> <span class="o">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> ! has_node<span class="p">;</span> <span class="k">then</span>
</span></span><span class="line"><span class="cl">        skip_lang <span class="s2">&#34;Node.js&#34;</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span>
</span></span><span class="line"><span class="cl">    <span class="k">fi</span>
</span></span><span class="line"><span class="cl">    info <span class="s2">&#34;Installing Node.js/TypeScript LSPs...&#34;</span>
</span></span><span class="line"><span class="cl">    
</span></span><span class="line"><span class="cl">    install_npm typescript
</span></span><span class="line"><span class="cl">    install_npm typescript-language-server
</span></span><span class="line"><span class="cl">    install_npm vscode-langservers-extracted  <span class="c1"># HTML, CSS, JSON, ESLint</span>
</span></span><span class="line"><span class="cl">    install_npm <span class="s2">&#34;@tailwindcss/language-server&#34;</span>
</span></span><span class="line"><span class="cl">    install_npm <span class="s2">&#34;@vue/language-server&#34;</span>
</span></span><span class="line"><span class="cl">    install_npm svelte-language-server
</span></span><span class="line"><span class="cl">    install_npm graphql-language-service-cli
</span></span><span class="line"><span class="cl">    install_npm <span class="s2">&#34;@prisma/language-server&#34;</span>
</span></span><span class="line"><span class="cl">    install_npm emmet-ls
</span></span><span class="line"><span class="cl"><span class="o">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># ─────────────────────────────────────────────────────────────</span>
</span></span><span class="line"><span class="cl"><span class="c1"># Java LSPs</span>
</span></span><span class="line"><span class="cl"><span class="c1"># ─────────────────────────────────────────────────────────────</span>
</span></span><span class="line"><span class="cl">install_java_lsps<span class="o">()</span> <span class="o">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> ! has_java<span class="p">;</span> <span class="k">then</span>
</span></span><span class="line"><span class="cl">        skip_lang <span class="s2">&#34;Java&#34;</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span>
</span></span><span class="line"><span class="cl">    <span class="k">fi</span>
</span></span><span class="line"><span class="cl">    info <span class="s2">&#34;Installing Java LSPs...&#34;</span>
</span></span><span class="line"><span class="cl">    install_yay jdtls
</span></span><span class="line"><span class="cl"><span class="o">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># ─────────────────────────────────────────────────────────────</span>
</span></span><span class="line"><span class="cl"><span class="c1"># Kotlin LSPs</span>
</span></span><span class="line"><span class="cl"><span class="c1"># ─────────────────────────────────────────────────────────────</span>
</span></span><span class="line"><span class="cl">install_kotlin_lsps<span class="o">()</span> <span class="o">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> ! has_kotlin<span class="p">;</span> <span class="k">then</span>
</span></span><span class="line"><span class="cl">        skip_lang <span class="s2">&#34;Kotlin&#34;</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span>
</span></span><span class="line"><span class="cl">    <span class="k">fi</span>
</span></span><span class="line"><span class="cl">    info <span class="s2">&#34;Installing Kotlin LSPs...&#34;</span>
</span></span><span class="line"><span class="cl">    install_yay kotlin-language-server
</span></span><span class="line"><span class="cl"><span class="o">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># ─────────────────────────────────────────────────────────────</span>
</span></span><span class="line"><span class="cl"><span class="c1"># Ruby LSPs</span>
</span></span><span class="line"><span class="cl"><span class="c1"># ─────────────────────────────────────────────────────────────</span>
</span></span><span class="line"><span class="cl">install_ruby_lsps<span class="o">()</span> <span class="o">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> ! has_ruby<span class="p">;</span> <span class="k">then</span>
</span></span><span class="line"><span class="cl">        skip_lang <span class="s2">&#34;Ruby&#34;</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span>
</span></span><span class="line"><span class="cl">    <span class="k">fi</span>
</span></span><span class="line"><span class="cl">    info <span class="s2">&#34;Installing Ruby LSPs...&#34;</span>
</span></span><span class="line"><span class="cl">    install_gem solargraph
</span></span><span class="line"><span class="cl">    install_gem ruby-lsp
</span></span><span class="line"><span class="cl"><span class="o">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># ─────────────────────────────────────────────────────────────</span>
</span></span><span class="line"><span class="cl"><span class="c1"># PHP LSPs</span>
</span></span><span class="line"><span class="cl"><span class="c1"># ─────────────────────────────────────────────────────────────</span>
</span></span><span class="line"><span class="cl">install_php_lsps<span class="o">()</span> <span class="o">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> ! has_php<span class="p">;</span> <span class="k">then</span>
</span></span><span class="line"><span class="cl">        skip_lang <span class="s2">&#34;PHP&#34;</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span>
</span></span><span class="line"><span class="cl">    <span class="k">fi</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> ! has_node<span class="p">;</span> <span class="k">then</span>
</span></span><span class="line"><span class="cl">        warn <span class="s2">&#34;PHP LSP (intelephense) requires npm, skipping&#34;</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span>
</span></span><span class="line"><span class="cl">    <span class="k">fi</span>
</span></span><span class="line"><span class="cl">    info <span class="s2">&#34;Installing PHP LSPs...&#34;</span>
</span></span><span class="line"><span class="cl">    install_npm intelephense
</span></span><span class="line"><span class="cl"><span class="o">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># ─────────────────────────────────────────────────────────────</span>
</span></span><span class="line"><span class="cl"><span class="c1"># Lua LSPs</span>
</span></span><span class="line"><span class="cl"><span class="c1"># ─────────────────────────────────────────────────────────────</span>
</span></span><span class="line"><span class="cl">install_lua_lsps<span class="o">()</span> <span class="o">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> ! has_lua<span class="p">;</span> <span class="k">then</span>
</span></span><span class="line"><span class="cl">        skip_lang <span class="s2">&#34;Lua&#34;</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span>
</span></span><span class="line"><span class="cl">    <span class="k">fi</span>
</span></span><span class="line"><span class="cl">    info <span class="s2">&#34;Installing Lua LSPs...&#34;</span>
</span></span><span class="line"><span class="cl">    install_pacman lua-language-server
</span></span><span class="line"><span class="cl"><span class="o">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># ─────────────────────────────────────────────────────────────</span>
</span></span><span class="line"><span class="cl"><span class="c1"># Zig LSPs</span>
</span></span><span class="line"><span class="cl"><span class="c1"># ─────────────────────────────────────────────────────────────</span>
</span></span><span class="line"><span class="cl">install_zig_lsps<span class="o">()</span> <span class="o">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> ! has_zig<span class="p">;</span> <span class="k">then</span>
</span></span><span class="line"><span class="cl">        skip_lang <span class="s2">&#34;Zig&#34;</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span>
</span></span><span class="line"><span class="cl">    <span class="k">fi</span>
</span></span><span class="line"><span class="cl">    info <span class="s2">&#34;Installing Zig LSPs...&#34;</span>
</span></span><span class="line"><span class="cl">    install_pacman zls
</span></span><span class="line"><span class="cl"><span class="o">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># ─────────────────────────────────────────────────────────────</span>
</span></span><span class="line"><span class="cl"><span class="c1"># Haskell LSPs</span>
</span></span><span class="line"><span class="cl"><span class="c1"># ─────────────────────────────────────────────────────────────</span>
</span></span><span class="line"><span class="cl">install_haskell_lsps<span class="o">()</span> <span class="o">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> ! has_haskell<span class="p">;</span> <span class="k">then</span>
</span></span><span class="line"><span class="cl">        skip_lang <span class="s2">&#34;Haskell&#34;</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span>
</span></span><span class="line"><span class="cl">    <span class="k">fi</span>
</span></span><span class="line"><span class="cl">    info <span class="s2">&#34;Installing Haskell LSPs...&#34;</span>
</span></span><span class="line"><span class="cl">    install_yay haskell-language-server
</span></span><span class="line"><span class="cl"><span class="o">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># ─────────────────────────────────────────────────────────────</span>
</span></span><span class="line"><span class="cl"><span class="c1"># Elixir LSPs</span>
</span></span><span class="line"><span class="cl"><span class="c1"># ─────────────────────────────────────────────────────────────</span>
</span></span><span class="line"><span class="cl">install_elixir_lsps<span class="o">()</span> <span class="o">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> ! has_elixir<span class="p">;</span> <span class="k">then</span>
</span></span><span class="line"><span class="cl">        skip_lang <span class="s2">&#34;Elixir&#34;</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span>
</span></span><span class="line"><span class="cl">    <span class="k">fi</span>
</span></span><span class="line"><span class="cl">    info <span class="s2">&#34;Installing Elixir LSPs...&#34;</span>
</span></span><span class="line"><span class="cl">    install_yay elixir-ls
</span></span><span class="line"><span class="cl"><span class="o">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># ─────────────────────────────────────────────────────────────</span>
</span></span><span class="line"><span class="cl"><span class="c1"># Scala LSPs</span>
</span></span><span class="line"><span class="cl"><span class="c1"># ─────────────────────────────────────────────────────────────</span>
</span></span><span class="line"><span class="cl">install_scala_lsps<span class="o">()</span> <span class="o">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> ! has_scala<span class="p">;</span> <span class="k">then</span>
</span></span><span class="line"><span class="cl">        skip_lang <span class="s2">&#34;Scala&#34;</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span>
</span></span><span class="line"><span class="cl">    <span class="k">fi</span>
</span></span><span class="line"><span class="cl">    info <span class="s2">&#34;Installing Scala LSPs...&#34;</span>
</span></span><span class="line"><span class="cl">    install_yay metals
</span></span><span class="line"><span class="cl"><span class="o">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># ─────────────────────────────────────────────────────────────</span>
</span></span><span class="line"><span class="cl"><span class="c1"># C# / F# (.NET) LSPs</span>
</span></span><span class="line"><span class="cl"><span class="c1"># ─────────────────────────────────────────────────────────────</span>
</span></span><span class="line"><span class="cl">install_dotnet_lsps<span class="o">()</span> <span class="o">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> ! has_dotnet<span class="p">;</span> <span class="k">then</span>
</span></span><span class="line"><span class="cl">        skip_lang <span class="s2">&#34;.NET (C#/F#)&#34;</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span>
</span></span><span class="line"><span class="cl">    <span class="k">fi</span>
</span></span><span class="line"><span class="cl">    info <span class="s2">&#34;Installing .NET LSPs...&#34;</span>
</span></span><span class="line"><span class="cl">    install_yay omnisharp-roslyn
</span></span><span class="line"><span class="cl">    install_yay fsautocomplete
</span></span><span class="line"><span class="cl"><span class="o">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># ─────────────────────────────────────────────────────────────</span>
</span></span><span class="line"><span class="cl"><span class="c1"># OCaml LSPs</span>
</span></span><span class="line"><span class="cl"><span class="c1"># ─────────────────────────────────────────────────────────────</span>
</span></span><span class="line"><span class="cl">install_ocaml_lsps<span class="o">()</span> <span class="o">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> ! has_ocaml<span class="p">;</span> <span class="k">then</span>
</span></span><span class="line"><span class="cl">        skip_lang <span class="s2">&#34;OCaml&#34;</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span>
</span></span><span class="line"><span class="cl">    <span class="k">fi</span>
</span></span><span class="line"><span class="cl">    info <span class="s2">&#34;Installing OCaml LSPs...&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> command_exists opam<span class="p">;</span> <span class="k">then</span>
</span></span><span class="line"><span class="cl">        opam install ocaml-lsp-server -y <span class="o">&amp;&amp;</span> success <span class="s2">&#34;ocaml-lsp-server&#34;</span> <span class="o">||</span> warn <span class="s2">&#34;Failed&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="k">else</span>
</span></span><span class="line"><span class="cl">        install_yay ocaml-lsp-server
</span></span><span class="line"><span class="cl">    <span class="k">fi</span>
</span></span><span class="line"><span class="cl"><span class="o">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># ─────────────────────────────────────────────────────────────</span>
</span></span><span class="line"><span class="cl"><span class="c1"># Clojure LSPs</span>
</span></span><span class="line"><span class="cl"><span class="c1"># ─────────────────────────────────────────────────────────────</span>
</span></span><span class="line"><span class="cl">install_clojure_lsps<span class="o">()</span> <span class="o">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> ! has_clojure<span class="p">;</span> <span class="k">then</span>
</span></span><span class="line"><span class="cl">        skip_lang <span class="s2">&#34;Clojure&#34;</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span>
</span></span><span class="line"><span class="cl">    <span class="k">fi</span>
</span></span><span class="line"><span class="cl">    info <span class="s2">&#34;Installing Clojure LSPs...&#34;</span>
</span></span><span class="line"><span class="cl">    install_yay clojure-lsp-bin
</span></span><span class="line"><span class="cl"><span class="o">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># ─────────────────────────────────────────────────────────────</span>
</span></span><span class="line"><span class="cl"><span class="c1"># Nix LSPs</span>
</span></span><span class="line"><span class="cl"><span class="c1"># ─────────────────────────────────────────────────────────────</span>
</span></span><span class="line"><span class="cl">install_nix_lsps<span class="o">()</span> <span class="o">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> ! has_nix<span class="p">;</span> <span class="k">then</span>
</span></span><span class="line"><span class="cl">        skip_lang <span class="s2">&#34;Nix&#34;</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span>
</span></span><span class="line"><span class="cl">    <span class="k">fi</span>
</span></span><span class="line"><span class="cl">    info <span class="s2">&#34;Installing Nix LSPs...&#34;</span>
</span></span><span class="line"><span class="cl">    install_pacman nil
</span></span><span class="line"><span class="cl"><span class="o">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># ─────────────────────────────────────────────────────────────</span>
</span></span><span class="line"><span class="cl"><span class="c1"># Bash LSPs</span>
</span></span><span class="line"><span class="cl"><span class="c1"># ─────────────────────────────────────────────────────────────</span>
</span></span><span class="line"><span class="cl">install_bash_lsps<span class="o">()</span> <span class="o">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> ! has_bash<span class="p">;</span> <span class="k">then</span>
</span></span><span class="line"><span class="cl">        skip_lang <span class="s2">&#34;Bash&#34;</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span>
</span></span><span class="line"><span class="cl">    <span class="k">fi</span>
</span></span><span class="line"><span class="cl">    info <span class="s2">&#34;Installing Bash LSPs...&#34;</span>
</span></span><span class="line"><span class="cl">    install_pacman bash-language-server
</span></span><span class="line"><span class="cl"><span class="o">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># ─────────────────────────────────────────────────────────────</span>
</span></span><span class="line"><span class="cl"><span class="c1"># Terraform LSPs</span>
</span></span><span class="line"><span class="cl"><span class="c1"># ─────────────────────────────────────────────────────────────</span>
</span></span><span class="line"><span class="cl">install_terraform_lsps<span class="o">()</span> <span class="o">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> ! has_terraform<span class="p">;</span> <span class="k">then</span>
</span></span><span class="line"><span class="cl">        skip_lang <span class="s2">&#34;Terraform&#34;</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span>
</span></span><span class="line"><span class="cl">    <span class="k">fi</span>
</span></span><span class="line"><span class="cl">    info <span class="s2">&#34;Installing Terraform LSPs...&#34;</span>
</span></span><span class="line"><span class="cl">    install_pacman terraform-ls
</span></span><span class="line"><span class="cl"><span class="o">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># ─────────────────────────────────────────────────────────────</span>
</span></span><span class="line"><span class="cl"><span class="c1"># LaTeX LSPs</span>
</span></span><span class="line"><span class="cl"><span class="c1"># ─────────────────────────────────────────────────────────────</span>
</span></span><span class="line"><span class="cl">install_latex_lsps<span class="o">()</span> <span class="o">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> ! has_latex<span class="p">;</span> <span class="k">then</span>
</span></span><span class="line"><span class="cl">        skip_lang <span class="s2">&#34;LaTeX&#34;</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span>
</span></span><span class="line"><span class="cl">    <span class="k">fi</span>
</span></span><span class="line"><span class="cl">    info <span class="s2">&#34;Installing LaTeX LSPs...&#34;</span>
</span></span><span class="line"><span class="cl">    install_pacman texlab
</span></span><span class="line"><span class="cl"><span class="o">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># ─────────────────────────────────────────────────────────────</span>
</span></span><span class="line"><span class="cl"><span class="c1"># Docker LSPs</span>
</span></span><span class="line"><span class="cl"><span class="c1"># ─────────────────────────────────────────────────────────────</span>
</span></span><span class="line"><span class="cl">install_docker_lsps<span class="o">()</span> <span class="o">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> ! has_docker<span class="p">;</span> <span class="k">then</span>
</span></span><span class="line"><span class="cl">        skip_lang <span class="s2">&#34;Docker&#34;</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span>
</span></span><span class="line"><span class="cl">    <span class="k">fi</span>
</span></span><span class="line"><span class="cl">    info <span class="s2">&#34;Installing Docker LSPs...&#34;</span>
</span></span><span class="line"><span class="cl">    install_yay dockerfile-language-server
</span></span><span class="line"><span class="cl"><span class="o">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># ─────────────────────────────────────────────────────────────</span>
</span></span><span class="line"><span class="cl"><span class="c1"># Ansible LSPs</span>
</span></span><span class="line"><span class="cl"><span class="c1"># ─────────────────────────────────────────────────────────────</span>
</span></span><span class="line"><span class="cl">install_ansible_lsps<span class="o">()</span> <span class="o">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> ! has_ansible<span class="p">;</span> <span class="k">then</span>
</span></span><span class="line"><span class="cl">        skip_lang <span class="s2">&#34;Ansible&#34;</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span>
</span></span><span class="line"><span class="cl">    <span class="k">fi</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> ! has_node<span class="p">;</span> <span class="k">then</span>
</span></span><span class="line"><span class="cl">        warn <span class="s2">&#34;Ansible LSP requires npm, skipping&#34;</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span>
</span></span><span class="line"><span class="cl">    <span class="k">fi</span>
</span></span><span class="line"><span class="cl">    info <span class="s2">&#34;Installing Ansible LSPs...&#34;</span>
</span></span><span class="line"><span class="cl">    install_npm <span class="s2">&#34;@ansible/ansible-language-server&#34;</span>
</span></span><span class="line"><span class="cl"><span class="o">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># ─────────────────────────────────────────────────────────────</span>
</span></span><span class="line"><span class="cl"><span class="c1"># SQL LSPs</span>
</span></span><span class="line"><span class="cl"><span class="c1"># ─────────────────────────────────────────────────────────────</span>
</span></span><span class="line"><span class="cl">install_sql_lsps<span class="o">()</span> <span class="o">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> ! has_sql<span class="p">;</span> <span class="k">then</span>
</span></span><span class="line"><span class="cl">        skip_lang <span class="s2">&#34;SQL (psql/mysql/sqlite)&#34;</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span>
</span></span><span class="line"><span class="cl">    <span class="k">fi</span>
</span></span><span class="line"><span class="cl">    info <span class="s2">&#34;Installing SQL LSPs...&#34;</span>
</span></span><span class="line"><span class="cl">    install_pacman sqls
</span></span><span class="line"><span class="cl"><span class="o">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># ─────────────────────────────────────────────────────────────</span>
</span></span><span class="line"><span class="cl"><span class="c1"># Generic config file LSPs (always install)</span>
</span></span><span class="line"><span class="cl"><span class="c1"># ─────────────────────────────────────────────────────────────</span>
</span></span><span class="line"><span class="cl">install_generic_lsps<span class="o">()</span> <span class="o">{</span>
</span></span><span class="line"><span class="cl">    info <span class="s2">&#34;Installing generic config LSPs (YAML, TOML, JSON, Markdown, XML)...&#34;</span>
</span></span><span class="line"><span class="cl">    install_pacman yaml-language-server
</span></span><span class="line"><span class="cl">    install_pacman taplo               <span class="c1"># TOML</span>
</span></span><span class="line"><span class="cl">    install_pacman marksman            <span class="c1"># Markdown</span>
</span></span><span class="line"><span class="cl">    install_yay lemminx                <span class="c1"># XML</span>
</span></span><span class="line"><span class="cl"><span class="o">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># ─────────────────────────────────────────────────────────────</span>
</span></span><span class="line"><span class="cl"><span class="c1"># Main</span>
</span></span><span class="line"><span class="cl"><span class="c1"># ─────────────────────────────────────────────────────────────</span>
</span></span><span class="line"><span class="cl">main<span class="o">()</span> <span class="o">{</span>
</span></span><span class="line"><span class="cl">    <span class="nb">echo</span> <span class="s2">&#34;═══════════════════════════════════════════════════════════&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="nb">echo</span> <span class="s2">&#34;         LSP Installer for Arch Linux + Mise&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="nb">echo</span> <span class="s2">&#34;    (Only installs LSPs for detected languages)&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="nb">echo</span> <span class="s2">&#34;═══════════════════════════════════════════════════════════&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="nb">echo</span>
</span></span><span class="line"><span class="cl">    
</span></span><span class="line"><span class="cl">    <span class="c1"># Language-specific LSPs</span>
</span></span><span class="line"><span class="cl">    install_c_lsps
</span></span><span class="line"><span class="cl">    install_rust_lsps
</span></span><span class="line"><span class="cl">    install_go_lsps
</span></span><span class="line"><span class="cl">    install_python_lsps
</span></span><span class="line"><span class="cl">    install_node_lsps
</span></span><span class="line"><span class="cl">    install_java_lsps
</span></span><span class="line"><span class="cl">    install_kotlin_lsps
</span></span><span class="line"><span class="cl">    install_ruby_lsps
</span></span><span class="line"><span class="cl">    install_php_lsps
</span></span><span class="line"><span class="cl">    install_lua_lsps
</span></span><span class="line"><span class="cl">    install_zig_lsps
</span></span><span class="line"><span class="cl">    install_haskell_lsps
</span></span><span class="line"><span class="cl">    install_elixir_lsps
</span></span><span class="line"><span class="cl">    install_scala_lsps
</span></span><span class="line"><span class="cl">    install_dotnet_lsps
</span></span><span class="line"><span class="cl">    install_ocaml_lsps
</span></span><span class="line"><span class="cl">    install_clojure_lsps
</span></span><span class="line"><span class="cl">    install_nix_lsps
</span></span><span class="line"><span class="cl">    install_bash_lsps
</span></span><span class="line"><span class="cl">    install_terraform_lsps
</span></span><span class="line"><span class="cl">    install_latex_lsps
</span></span><span class="line"><span class="cl">    install_docker_lsps
</span></span><span class="line"><span class="cl">    install_ansible_lsps
</span></span><span class="line"><span class="cl">    install_sql_lsps
</span></span><span class="line"><span class="cl">    
</span></span><span class="line"><span class="cl">    <span class="nb">echo</span>
</span></span><span class="line"><span class="cl">    <span class="c1"># Always-useful LSPs for config files</span>
</span></span><span class="line"><span class="cl">    install_generic_lsps
</span></span><span class="line"><span class="cl">    
</span></span><span class="line"><span class="cl">    <span class="nb">echo</span>
</span></span><span class="line"><span class="cl">    <span class="nb">echo</span> <span class="s2">&#34;═══════════════════════════════════════════════════════════&#34;</span>
</span></span><span class="line"><span class="cl">    success <span class="s2">&#34;LSP installation complete!&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="nb">echo</span> <span class="s2">&#34;═══════════════════════════════════════════════════════════&#34;</span>
</span></span><span class="line"><span class="cl"><span class="o">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">main <span class="s2">&#34;</span><span class="nv">$@</span><span class="s2">&#34;</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>In theory that&rsquo;s all there is to it. If anyone knows a better way, drop it in the comments below.</p>
]]></content:encoded><category>coding-agents</category><category>automation</category><category>developer-tools</category></item><item><title>Omarchy 2.0 - LazyVim Basics</title><link>https://akitaonrails.github.io/en/2025/09/12/omarchy-2-0-lazyvim-basics/</link><guid isPermaLink="true">https://akitaonrails.github.io/en/2025/09/12/omarchy-2-0-lazyvim-basics/</guid><pubDate>Fri, 12 Sep 2025 15:00:00 -0300</pubDate><description>&lt;p&gt;Damn it, I said the previous post would be the last one in the &lt;a href="https://akitaonrails.github.io/en/tags/omarchy/"&gt;Omarchy&lt;/a&gt; series, but I figured this was a good chance to evangelize a bit about Vim too. I&amp;rsquo;ve already recommended following &lt;a href="https://www.youtube.com/@EustaquioRangel"target="_blank" rel="noopener"&gt;@Taq&amp;rsquo;s channel&lt;/a&gt;, where he explains in much more depth how NeoVim works. There&amp;rsquo;s also &lt;a href="https://github.com/ThePrimeagen/vim-be-good"target="_blank" rel="noopener"&gt;Primeagen&amp;rsquo;s &amp;ldquo;vim-be-good&amp;rdquo; tutorial&lt;/a&gt;. That second one in particular is an interactive tutorial inside NeoVim itself, to practice navigation - which many people find hard at first.&lt;/p&gt;</description><content:encoded><![CDATA[<p>Damn it, I said the previous post would be the last one in the <a href="/en/tags/omarchy/">Omarchy</a> series, but I figured this was a good chance to evangelize a bit about Vim too. I&rsquo;ve already recommended following <a href="https://www.youtube.com/@EustaquioRangel"target="_blank" rel="noopener">@Taq&rsquo;s channel</a>, where he explains in much more depth how NeoVim works. There&rsquo;s also <a href="https://github.com/ThePrimeagen/vim-be-good"target="_blank" rel="noopener">Primeagen&rsquo;s &ldquo;vim-be-good&rdquo; tutorial</a>. That second one in particular is an interactive tutorial inside NeoVim itself, to practice navigation - which many people find hard at first.</p>
<p>I&rsquo;ll do only this one article about it and I don&rsquo;t intend to cover more than the tip of the iceberg. The idea is to serve whoever is coming from other editors like Sublime Text or VS Code and can&rsquo;t even start navigating or even quit Vim lol 🤣.</p>
<h3>Initial Commands<span class="hx:absolute hx:-mt-20" id="initial-commands"></span>
    <a href="#initial-commands" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>As I said in the <a href="https://akitaonrails.com/en/2025/09/07/omarchy-2-0-lazyvim-lazyextras/"target="_blank" rel="noopener">previous post about LazyVim</a>, I&rsquo;ll assume you already understand at least how to install support for your language with <strong>LazyExtras</strong> and already learned to version things using <a href="https://akitaonrails.com/en/2025/09/07/omarchy-2-0-mise-for-organizing-dev-environments/"target="_blank" rel="noopener"><strong>Mise</strong></a>.</p>
<p>Without even getting into LazyVim, the first thing to know is that it installs all the relevant configurations in the <code>~/.config/nvim</code> directory. Normally you don&rsquo;t need to touch anything there. Leave files like <code>lazyvim.json</code> alone. Notice that it does the same thing as any NPM out there: there&rsquo;s a <code>lazy-lock.json</code> file that declares the version/commit of each installed plugin. LazyVim does something similar to an <code>npm install</code>. Just a curiosity so you know how it organizes itself.</p>
<p>If you need to customize something, it&rsquo;s usually going to be in the <code>~/.config/nvim/lua/config</code> directory. That&rsquo;s where I added Mise support, for example:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">~/.config/nvim
</span></span><span class="line"><span class="cl">❯ cat lua/config/mise.lua
</span></span><span class="line"><span class="cl">-- Prepend mise shims to PATH
</span></span><span class="line"><span class="cl">vim.env.PATH <span class="o">=</span> vim.env.HOME .. <span class="s2">&#34;/.local/share/mise/shims:&#34;</span> .. vim.env.PATH</span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>They&rsquo;ll always be scripts written in Lua. And you don&rsquo;t even need to know Lua deeply. At a glance it&rsquo;s a very simple language, not very different from Python or Javascript and any programmer should be able to read any snippet without any problem. Besides, in most cases you&rsquo;ll be copying configurations you got from the documentation, wiki or ChatGPT itself, so you just need to know that things go in this location.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20250912110425_screenshot-2025-09-12_11-04-07.png" alt="primeiros passos"  loading="lazy" /></p>
<p>Understand that NeoVim has the concept of the &ldquo;<strong>Leader</strong>&rdquo; key, a key that precedes hotkeys for other commands (there&rsquo;s also <strong>localleader</strong> which is backslash <strong>\</strong>). This is configurable but in LazyVim the Leader is the <strong>&ldquo;Space&rdquo;</strong> key. In a lot of documentation we&rsquo;ll see people saying <em>&ldquo;press Leader-w&rdquo;</em>, which means <strong>Space+w</strong> and now you know what that means.</p>
<p>To open a file there are at least 3 different ways, 2 of them shown in the image above:</p>
<blockquote>
  <p><strong>Space+E</strong> opens <strong>NeoTree</strong>, which is that sidebar on the left that looks like Windows Explorer. You can navigate with the keyboard or even with the mouse. Find your file and press &ldquo;Enter&rdquo; to open it, then &ldquo;Space+E&rdquo; again to hide the sidebar. If you want to know how to create a new file, a new subdirectory, rename things and so on, type <strong>?</strong> (question mark) to see this help:</p>

</blockquote>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20250912142438_neotree.gif" alt="NeoTree"  loading="lazy" /></p>
<p>The third way is manually with the <strong>:e</strong> command followed by the file name in the local directory. It has autocomplete too, this is the fastest way, if you know what you&rsquo;re looking for.</p>
<p>Whenever you want to cancel anything or close &ldquo;floating windows&rdquo; (pop-ups, dialog boxes). Just press &ldquo;Esc&rdquo;. Esc is fundamental in NeoVim.</p>
<p>Once a file is open, it sits in the <strong>Buffer</strong>. Think of Buffer as &ldquo;Open Tabs&rdquo; in your VS Code. To navigate through Buffers (like alt+tab between your already-opened files) it&rsquo;s simple:</p>
<ul>
<li><strong>]+b</strong> for next &ldquo;tab&rdquo; (next Buffer)</li>
<li><strong>[+b</strong> previous Buffer</li>
<li><strong>Space+bd</strong> to &ldquo;close the tab&rdquo; (close the Buffer)</li>
<li><strong>Space+bo</strong> to stay where you are and close the other buffers</li>
</ul>
<p>Open as many files as you want. If one of them is one of those huge logs you opened by accident, <code>Space+bd</code> to close it and done.</p>
<p>Speaking of closing, <strong>how do you exit NeoVim?</strong> There are several ways:</p>
<ul>
<li><strong>Space+q</strong></li>
<li><strong>:q</strong></li>
<li><strong>:q!</strong></li>
</ul>
<p>The difference: the first is the custom way in LazyVim. The second is the standard way using the &ldquo;commands&rdquo; feature that always starts with &ldquo;colon&rdquo;. And the third is if you modified something in the file but want to cancel, exit without saving anything, hence the exclamation mark.</p>
<p>Normally I use <strong>:wq</strong> which means &ldquo;write&rdquo; and &ldquo;quit&rdquo;. So it first saves the changes to the file and then quits the program. It&rsquo;s useful when I&rsquo;m just quickly editing a config file.</p>
<h3>Basic Navigation<span class="hx:absolute hx:-mt-20" id="basic-navigation"></span>
    <a href="#basic-navigation" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Now I have a file open. How do I navigate through it? First, how do I go to the end of the file and then back to the beginning? This is something I use a lot, just type <strong>Shift+g</strong> to go to the end of the file and then <strong>gg</strong> to go back to the beginning. Simple as that.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20250912143147_home-end.gif" alt="home-end"  loading="lazy" /></p>
<p>Now let&rsquo;s learn several commands at once:</p>
<ul>
<li>Type <strong>v</strong>. This starts the <strong>&ldquo;visual mode&rdquo;</strong> which, in practice, means starting to select from wherever your cursor is.</li>
<li>Type <strong>j</strong>. Which is the equivalent of &ldquo;arrow down&rdquo; to go to the line below. You&rsquo;ve probably heard that in Vim you navigate with &ldquo;hjkl&rdquo; which are, respectively, left, down, up, right.</li>
<li>Type <strong>x</strong>. Which is the equivalent of &ldquo;cut&rdquo; and putting the content in the clipboard. Having done that, typing <strong>p</strong> gives you &ldquo;paste&rdquo;.</li>
<li>Type <strong>u</strong>. Which is the most-used command: <strong>Undo</strong> or undoing the last modification.</li>
</ul>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20250912143741_marcar-apagar.gif" alt="marcar-apagar"  loading="lazy" /></p>
<p>All of this works in what&rsquo;s called <strong>&ldquo;command mode&rdquo;</strong>, which is the default mode Vim opens every file in. In this mode you can&rsquo;t type any text. As you can see, each letter by itself is a command, like &ldquo;x&rdquo; for cut or &ldquo;p&rdquo; for paste.</p>
<p>To type, you first need to press <strong>i</strong> (just the lowercase &ldquo;i&rdquo; letter), which then switches from command mode to <strong>&ldquo;edit mode&rdquo;</strong>. Now just type your text normally, like in any editor. When you want some command, just press <strong>ESC</strong> to go back to command mode. We&rsquo;ll be doing this all the time, which is why a lot of people remap the &ldquo;caps lock&rdquo; key on the keyboard to be ESC so it&rsquo;s easy to just tap with your left pinky.</p>
<h3>Combining Commands<span class="hx:absolute hx:-mt-20" id="combining-commands"></span>
    <a href="#combining-commands" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><blockquote>
  <p>Still in command mode, how do we navigate through the file more easily?</p>

</blockquote>
<p>Beyond the &ldquo;hjkl&rdquo; keys, we can navigate more easily using <strong>b</strong> for &ldquo;previous word&rdquo; or <strong>w</strong> for next word:</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20250912144226_words.gif" alt="words"  loading="lazy" /></p>
<p>Command mode lets you combine commands, so we can do:</p>
<ul>
<li><strong>dw</strong> to delete the next word</li>
<li><strong>db</strong> to delete the previous word</li>
<li><strong>d4w</strong> to delete the next 4 words</li>
<li><strong>d4j</strong> to delete the next 4 lines down</li>
</ul>
<p><a href="https://github.com/ThePrimeagen/vim-be-good"target="_blank" rel="noopener">Primeagen&rsquo;s tutorial</a> has several exercises for this kind of navigation, I recommend practicing. In VS Code everyone is used to first grabbing the mouse, marking the block they want to delete visually, then pressing delete or backspace. In Vim, we look at where the cursor is, press ESC to be in command mode, and type the operation and the location. Test all the combinations you can imagine.</p>
<p>This is the <strong>paradigm shift</strong> that bothers the lazy. But once you&rsquo;ve learned this, you&rsquo;ll find it annoying to use an editor that forces you to use the mouse for basic things.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20250912144801_change.gif" alt="change in place"  loading="lazy" /></p>
<p>Now it gets more interesting: <em>what if instead of deleting a word, I want to replace the word where my cursor is with another word?</em></p>
<p>In a normal editor, you&rsquo;d mark it with the mouse (or use some combination like &ldquo;ctrl+shift+arrow&rdquo;), and type over it or delete the word.</p>
<p>In LazyVim there are plugins configured for more interesting things. In the video above see how I&rsquo;m replacing words <em>&ldquo;in-place&rdquo;</em>. You do this with the <strong>ciw</strong> command.</p>
<ul>
<li><strong>ciw</strong> deletes the entire word under the cursor and opens edit mode for you to type the replacement</li>
<li><strong>ce</strong> deletes from the cursor to the end of the word (preserves the beginning of the word) and also opens for you to type in its place</li>
<li><strong>Shift-c</strong> (capital C) deletes everything from your cursor to the end of the entire line and opens for you to type.</li>
</ul>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20250912145439_bloco.gif" alt="Mudar Bloco Vertical"  loading="lazy" /></p>
<p>But that still doesn&rsquo;t look thaaaat cool. What if you want to change only the first letter of several lines at the same time, for example, in the text of the video above, I want to change only the hyphen (&quot;-&quot;) of each tag line?</p>
<p>I said before that pressing <strong>v</strong> in command mode starts visual mode and you can select from there. But there&rsquo;s <strong>Ctrl+v</strong> which opens vertical block selection mode.</p>
<p>In this mode we use the &ldquo;hjkl&rdquo; keys normally, like <strong>j</strong> to go down, but instead of marking the next entire line, it marks only the character right below your cursor. Now I can delete with <strong>d</strong> and type <strong>Shift-i</strong> (capital &ldquo;I&rdquo;) to enter edit mode at the beginning of the block and replace with whatever I want.</p>
<p>LazyVim has plugins for comments, but this is another alternative if you want to add &ldquo;//&rdquo; or &ldquo;#&rdquo; at the beginning of several lines to comment out, for example. In this case, read about the <a href="https://github.com/folke/ts-comments.nvim"target="_blank" rel="noopener"><strong>ts-comments</strong></a> plugin for better options for commenting. To start a new comment block, type <strong>gco</strong> to add a comment below.</p>
<p><em>&ldquo;Block mode&rdquo;</em> as I showed above, is one of the things I use the most in code.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20250912150112_search-replace.gif" alt="Search and Replace"  loading="lazy" /></p>
<p>But only that is very little. What if you want to replace <strong>ALL IDENTICAL WORDS</strong> in the text at once. In the example video above, I want to replace &ldquo;domínio&rdquo; with &ldquo;DOMAIN&rdquo; and &ldquo;Cloudflare&rdquo; with &ldquo;AWS Amazon&rdquo;, how do I do that? This is &ldquo;Search and Replace&rdquo; that exists in every editor and in Vim it&rsquo;s very easy:</p>
<p>We type <strong>:%s/domínio/DOMAIN/</strong>.</p>
<p>If you&rsquo;re a programmer you&rsquo;ve probably seen this syntax before. It&rsquo;s the <strong>REGEX MATCH</strong> syntax. Yes, you have to know Regex (and no, it&rsquo;s not PCRE nor Unicode, it&rsquo;s NeoVim&rsquo;s own Regex dialect, but it&rsquo;s similar).</p>
<p>As I said before, &ldquo;colon&rdquo; opens the command-typing box, <strong>&quot;%s&quot;</strong> starts &ldquo;search with regex&rdquo; and between the slashes &ldquo;//&rdquo; first goes what you&rsquo;re looking for and then what you want to replace it with.</p>
<p>But that&rsquo;s the way in pure NeoVim; in LazyVim, there&rsquo;s the <a href=""><strong>grug-far</strong></a> plugin and you activate it with the <strong>SPACE+sr</strong> command:</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20250912150648_screenshot-2025-09-12_15-06-32.png" alt="grug-far"  loading="lazy" /></p>
<p>Now yes, more like VS Code, right? Use whichever you find easier.</p>
<h3>Conclusion<span class="hx:absolute hx:-mt-20" id="conclusion"></span>
    <a href="#conclusion" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>As I said, this is only the tip of the tip of the iceberg, the bare minimum of the bare minimum to at least start editing simple config files without opening Nano or VS Code just for that.</p>
<p>Read the LazyVim documentation. Check out the <a href="https://www.lazyvim.org/keymaps"target="_blank" rel="noopener">keymaps</a> to discover other commands. Pay attention to every letter you press in command mode, LazyVim shows the available options. For example, let&rsquo;s say I pressed <strong>g</strong> (goto), it will show a help in the bottom-right corner:</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20250912151849_screenshot-2025-09-12_15-18-38.png" alt="ajuda"  loading="lazy" /></p>
<p>This way you can always discover new commands or remember commands you rarely use. That&rsquo;s why I recommend LazyVim, which comes well configured to help you. The plugin that provides this feature is <a href="https://github.com/folke/which-key.nvim"target="_blank" rel="noopener"><strong>which-key</strong></a>, in case you want the same thing in a NeoVim you configured from scratch.</p>
<p>There are several <a href="https://vim.rtorr.com/"target="_blank" rel="noopener"><strong>Cheatsheets</strong></a> out there with tables of important command combinations. Worth exploring.</p>
<p>And there&rsquo;s more: LazyVim comes with dozens of <a href="https://www.lazyvim.org/plugins"target="_blank" rel="noopener">plugins</a> for formatting, linting, integrated LSP, integrated GIT, and much more. There&rsquo;s no way I can document each one here. Each of them has its own documentation on the LazyVim.org plugins page.</p>
<p>Again, don&rsquo;t forget to call <strong>:LazyExtras</strong> and install the optional plugins for your languages.</p>
]]></content:encoded><category>omarchy</category><category>developer-tools</category><category>tutorials</category></item><item><title>Omarchy 2.0 - TUIs (Terminal User Interface Apps)</title><link>https://akitaonrails.github.io/en/2025/09/09/omarchy-2-0-tuis/</link><guid isPermaLink="true">https://akitaonrails.github.io/en/2025/09/09/omarchy-2-0-tuis/</guid><pubDate>Tue, 09 Sep 2025 01:00:00 -0300</pubDate><description>&lt;p&gt;One of the most frustrating things for a Linux user is that there are very few well-made graphical apps. Look at Gimp or LibreOffice. They&amp;rsquo;re ugly, outdated, very similar to the first time I used them over 20 years ago.&lt;/p&gt;
&lt;p&gt;The more &amp;ldquo;modern&amp;rdquo; apps are basically canned web front-ends wrapped inside Electron. The problem? They&amp;rsquo;re &lt;strong&gt;HEAVY&lt;/strong&gt; and chew through RAM like there&amp;rsquo;s no tomorrow. Start opening Discord, Spotify, and a handful of these and see if your old 8GB notebook can keep up.&lt;/p&gt;</description><content:encoded><![CDATA[<p>One of the most frustrating things for a Linux user is that there are very few well-made graphical apps. Look at Gimp or LibreOffice. They&rsquo;re ugly, outdated, very similar to the first time I used them over 20 years ago.</p>
<p>The more &ldquo;modern&rdquo; apps are basically canned web front-ends wrapped inside Electron. The problem? They&rsquo;re <strong>HEAVY</strong> and chew through RAM like there&rsquo;s no tomorrow. Start opening Discord, Spotify, and a handful of these and see if your old 8GB notebook can keep up.</p>
<p>But, especially if you&rsquo;re a programmer, you should pay more attention to TUIs. At first, some will turn their nose up: <em>&ldquo;terminal apps are ugly, black and white, boxy, blegh&rdquo;</em></p>
<p>Twenty years ago, they&rsquo;d be right. But it&rsquo;s 2025 and today&rsquo;s terminals support 256 colors (more than enough), various resolutions and, most importantly, fonts, in particular <a href="https://www.nerdfonts.com/"target="_blank" rel="noopener">Nerd Fonts</a>, fonts that have icons inside. That&rsquo;s how a tool like <a href="https://github.com/eza-community/eza"target="_blank" rel="noopener">eza</a> works, which I use every day aliased to <code>ls</code> and looks like this:</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/screenshot-2025-08-29_16-50-25.png" alt="eza"  loading="lazy" /></p>
<p>And there&rsquo;s more: there are modern libraries, for several languages, like <a href="https://github.com/charmbracelet/bubbletea"target="_blank" rel="noopener"><strong>BubbleTea</strong></a>, a framework for building TUIs. Check their GitHub but they have the tools to make interfaces like this:</p>
<p><img src="https://camo.githubusercontent.com/e2b13cfb4ea64e98028ab21e0dca97a6af46d8eeb78ef092c5cd4669ea7b7bef/68747470733a2f2f73747566662e636861726d2e73682f627562626c657465612f627562626c657465612d6578616d706c652e676966" alt="BubbleTea"  loading="lazy" /></p>
<p>And if you just want a simple widget to complement a Bash script you&rsquo;re writing, they have <a href="https://github.com/charmbracelet/gum"target="_blank" rel="noopener"><strong>Gum</strong></a>, which lets you do interfaces like this:</p>
<p><img src="https://camo.githubusercontent.com/cea695e2df946b14838196a5cfb7d6608f03387ba42c7a7fb5afa6432371635c/68747470733a2f2f7668732e636861726d2e73682f7668732d31715935375272516c584375796473456744703638472e676966" alt="Gum"  loading="lazy" /></p>
<p>And to use it just install the binary and put lines like this in your script:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># Gum examples</span>
</span></span><span class="line"><span class="cl">gum choose <span class="s2">&#34;fix&#34;</span> <span class="s2">&#34;feat&#34;</span> <span class="s2">&#34;docs&#34;</span> <span class="s2">&#34;style&#34;</span> <span class="s2">&#34;refactor&#34;</span> <span class="s2">&#34;test&#34;</span> <span class="s2">&#34;chore&#34;</span> <span class="s2">&#34;revert&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">gum input --placeholder <span class="s2">&#34;scope&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">gum confirm <span class="s2">&#34;Commit changes?&#34;</span> <span class="o">&amp;&amp;</span> git commit -m <span class="s2">&#34;</span><span class="nv">$SUMMARY</span><span class="s2">&#34;</span> -m <span class="s2">&#34;</span><span class="nv">$DESCRIPTION</span><span class="s2">&#34;</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>And if you use <a href="https://akitaonrails.com/en/tags/omarchy/"target="_blank" rel="noopener"><strong>Omarchy</strong></a> they ship an extra feature for TUIs. Just hit &ldquo;SUPER+ALT+SPACE&rdquo; to bring up the main menu, then pick &ldquo;INSTALL&rdquo; and &ldquo;TUI&rdquo;. Or simply open the terminal and run:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>$OMARCHY_PATH/bin/omarchy-tui-install</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/screenshot-2025-09-08_23-22-50.png" alt="omarchy-tui-install"  loading="lazy" /></p>
<p>It&rsquo;ll ask for a name for the App and the command line to run. You can also pick icons at <a href="https://dashboardicons.com/"target="_blank" rel="noopener">Dashboard Icons</a>. Once registered that way, when you call the Rofi launcher with &ldquo;SUPER+SPACE&rdquo; and type &ldquo;lazy&rdquo;, LazyDocker shows up as if it were a regular app:</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/hdmi-a-3.png" alt="Rofi LazyDocker"  loading="lazy" /></p>
<p>And since Hyprland has no title bar or anything, TUI apps or web apps (there&rsquo;s <code>omarchy-webapp-install</code> too) open as if they were &ldquo;native&rdquo; apps:</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/screenshot-2025-09-09_00-49-28.png" alt="tiles windows"  loading="lazy" /></p>
<p>Read the <a href="https://learn.omacom.io/2/the-omarchy-manual/59/tuis"target="_blank" rel="noopener">TUIs</a> and <a href="https://learn.omacom.io/2/the-omarchy-manual/63/web-apps"target="_blank" rel="noopener">Web-Apps</a> sections in the Omarchy manual.</p>
<p>Obviously, this is only for those who prefer the feeling of running &ldquo;Apps&rdquo;, but it&rsquo;s the same thing as opening a Terminal and simply typing <code>lazydocker</code> on the command line - which is my preference. What these Omarchy scripts do is create a <code>.desktop</code> file at <code>~/.local/share/applications</code>. The <code>LazyDocker.desktop</code> example generates this:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>❯ cat ~/.local/share/applications/LazyDocker.desktop
[Desktop Entry]
Version=1.0
Name=LazyDocker
Comment=LazyDocker
Exec=alacritty --class TUI.tile -e lazydocker
Terminal=false
Type=Application
Icon=/home/akitaonrails/.local/share/applications/icons/LazyDocker.png
StartupNotify=true</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>If you don&rsquo;t want this launcher anymore, just delete the file or call the <code>$OMARCHY_PATH/bin/omarchy-tui-remove</code> script.</p>
<p>This feature is particularly interesting in Hyprland because, unlike GNOME or KDE, the window has no top title bar, so it doesn&rsquo;t give away that you&rsquo;re just opening a terminal or web browser. That&rsquo;s how it ships pre-configured with things like ChatGPT or Grok looking like &ldquo;native&rdquo; apps, when they&rsquo;re really just Chromium windows opening each one&rsquo;s URLs directly:</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/screenshot-2025-09-09_00-54-52.png" alt="WebApps Omarchy"  loading="lazy" /></p>
<h2>Some TUIs I like<span class="hx:absolute hx:-mt-20" id="some-tuis-i-like"></span>
    <a href="#some-tuis-i-like" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>In my opinion, since there are no pretty GUI apps for Linux, it&rsquo;s really better to use the respective web apps like Canva or ChatGPT that way, but more interesting is having actual TUIs. As I said, these days it&rsquo;s not hard to make pretty TUIs. For a programmer, the advantage is that you don&rsquo;t have to deal with front-end frameworks first, and second, you don&rsquo;t have to deploy anywhere on the internet.</p>
<p>TUIs are lightweight, use few machine resources, they&rsquo;re easy for any programmer to build, and you can have a home server or a server in some cloud, SSH in, and access the TUI, without having to deal with X11 or RDP or anything heavier just to get a GUI.</p>
<p>Some TUIs are obvious: in the <a href="https://akitaonrails.com/en/2025/09/07/omarchy-2-0-lazyvim-lazyextras/"target="_blank" rel="noopener">previous post</a> I already talked about <a href="https://www.lazyvim.org/"target="_blank" rel="noopener"><strong>LazyVim</strong></a> and how it&rsquo;s a text editor as competent and complete as VS Code, using only a fraction of the machine&rsquo;s resources. Everyone should know tools like HTOP or BTOP. Plus <a href="https://github.com/jesseduffield/lazygit"target="_blank" rel="noopener">LazyGit</a> or <a href="https://github.com/jesseduffield/lazydocker"target="_blank" rel="noopener">LazyDocker</a>. All of these already come in Omarchy.</p>
<p>But there&rsquo;s much more, for example, <a href="https://github.com/danvergara/dblab"target="_blank" rel="noopener"><strong>dblab</strong></a> which is a TUI database client for MySQL or Postgres:</p>
<p><img src="https://github.com/danvergara/dblab/raw/main/screenshots/dblab-cover.png" alt="dblab"  loading="lazy" /></p>
<p>Another similar one is <a href="https://github.com/jorgerojas26/lazysql"target="_blank" rel="noopener">LazySQL</a>, written in Go:</p>
<p><img src="https://github.com/jorgerojas26/lazysql/raw/main/images/lazysql.png" alt="LazySQL"  loading="lazy" /></p>
<p>Or if you prefer tools written in Rust, there&rsquo;s <a href="https://github.com/achristmascarl/rainfrog"target="_blank" rel="noopener"><strong>rainfrog</strong></a>:</p>
<p><img src="https://github.com/achristmascarl/rainfrog/raw/main/vhs/demo.gif" alt="rainfrog"  loading="lazy" /></p>
<p>For those who can&rsquo;t use CURL on the command line and prefer Postman to call and explore APIs, there&rsquo;s the TUI <a href="https://github.com/darrenburns/posting"target="_blank" rel="noopener"><strong>Posting</strong></a> that does the same thing:</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/422760155-78359ab0-5e0c-4c0b-a60b-dce06b11bbf5.png" alt="Posting"  loading="lazy" /></p>
<p>For those of us who run lots of Docker containers, I already mentioned LazyDocker, but there&rsquo;s also <a href="https://github.com/mrjackwills/oxker"target="_blank" rel="noopener"><strong>oxker</strong></a>:</p>
<p><img src="https://github.com/mrjackwills/oxker/raw/main/.github/demo_01.webp" alt="oxker"  loading="lazy" /></p>
<p>If you use Discord, there&rsquo;s <a href="https://github.com/ayn2op/discordo"target="_blank" rel="noopener"><strong>discordo</strong></a>:</p>
<p><img src="https://github.com/ayn2op/discordo/raw/main/.github/preview.png" alt="Discordo"  loading="lazy" /></p>
<p>Anyone who does a lot of Linux ricing has had to burn ISOs to USB sticks dozens of times; for that there&rsquo;s <code>dd</code> on the command line, but there&rsquo;s a cooler TUI called <a href="https://github.com/ifd3f/caligula"target="_blank" rel="noopener"><strong>Caligula</strong></a>:</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2025/09/09/omarchy-2-0-tuis/caligula-burning.png" alt="Caligula burning a disk image in the terminal: a “Burning… 251.7 MB” bar at the top, a write-speed graph oscillating up to 32 MB/s over ~12 seconds, and a Stats panel showing input my_cool.img.lz4, output /dev/sdb, average write of 20.2 MB/s, and an ETA of 24 seconds."  loading="lazy" /></p>
<p>If your SSD is filling up and you have no idea where the hell all that space is going, there are several tools to analyze and show you. One of them is <a href="https://github.com/dundee/gdu"target="_blank" rel="noopener"><strong>gdu</strong></a>:</p>
<p><img src="https://camo.githubusercontent.com/d8fa7d2f7bdd10dce45a81c2accf26d597b300b82e01b97a1288ff2f1fe06c57/68747470733a2f2f61736369696e656d612e6f72672f612f3338323733382e737667" alt="gdu"  loading="lazy" /></p>
<p>And the last one I thought was cool out of nostalgia is <a href="https://github.com/andmarti1424/sc-im"target="_blank" rel="noopener"><strong>sc-im</strong></a>; think Excel as a TUI or - for those of us who came from the 80s - think Lotus 1-2-3 but with Vim keybindings:</p>
<p><img src="https://github.com/andmarti1424/sc-im/raw/main/screenshots/scim-plot-graph.gif?raw=true" alt="sc-im"  loading="lazy" /></p>
<p>Why open Google Spreadsheets just to make a Todo list if you can do it in the Terminal?? TUIs are exceptional!</p>
<p>If you want to discover more TUIs check out <a href="https://github.com/rothgar/awesome-tuis/?tab=readme-ov-file"target="_blank" rel="noopener"><strong>awesome-tuis</strong></a> on GitHub:</p>
<p><a href="https://github.com/rothgar/awesome-tuis/?tab=readme-ov-file"target="_blank" rel="noopener"><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2025/09/09/omarchy-2-0-tuis/awesome-tuis-banner.png" alt="awesome tuis"  loading="lazy" /></a>
Again: zero need for heavy web front-ends for simple things. Nothing beats the simplicity of a command line. And with libraries like BubbleTea or Gum, it&rsquo;s now very easy for anyone to make a pretty app. And with Hyprland and Omarchy, everything stays integrated side-by-side with any other GUI app.</p>
<p>Getting a bit philosophical, the history of GUIs starts with <em>skeuomorphic</em> graphical interfaces that try to imitate objects from our daily life, particularly looking pseudo-3D, like Windows 95 was. The 2000s arrived and they started migrating to <em>flat</em> or <em>minimalist</em> interfaces, completely removing the skeuomorphism, making everything flat. That came mainly from Windows 8&rsquo;s Metro. And I think that&rsquo;s converging toward a more TUI-like style, coming full circle, going back to how it was on 70s terminals. Personally, I find that fascinating.</p>
]]></content:encoded><category>omarchy</category><category>developer-tools</category><category>linux</category></item><item><title>Omarchy 2.0 - Mise for Organizing Development Environments</title><link>https://akitaonrails.github.io/en/2025/09/07/omarchy-2-0-mise-for-organizing-dev-environments/</link><guid isPermaLink="true">https://akitaonrails.github.io/en/2025/09/07/omarchy-2-0-mise-for-organizing-dev-environments/</guid><pubDate>Sun, 07 Sep 2025 16:40:00 -0300</pubDate><description>&lt;p&gt;Continuing my posts about &lt;a href="https://www.akitaonrails.com/en/tags/omarchy/"target="_blank" rel="noopener"&gt;Omarchy&lt;/a&gt;, here&amp;rsquo;s another introductory post, this time about &lt;a href="https://mise.jdx.dev/getting-started.html"target="_blank" rel="noopener"&gt;Mise-en-place&lt;/a&gt;, which already comes pre-installed. On Omarchy, if you press &amp;ldquo;Super+Alt+Space&amp;rdquo; the main menu will open. Pick &amp;ldquo;Install&amp;rdquo; and then &amp;ldquo;Development&amp;rdquo; and you&amp;rsquo;ll see several languages/frameworks you can install, like Ruby on Rails or Go.&lt;/p&gt;
&lt;p&gt;But you don&amp;rsquo;t need to use these menus. Let me explain.&lt;/p&gt;
&lt;p&gt;On a regular Arch Linux or Ubuntu, an amateur would install ruby or python doing something like this:&lt;/p&gt;</description><content:encoded><![CDATA[<p>Continuing my posts about <a href="https://www.akitaonrails.com/en/tags/omarchy/"target="_blank" rel="noopener">Omarchy</a>, here&rsquo;s another introductory post, this time about <a href="https://mise.jdx.dev/getting-started.html"target="_blank" rel="noopener">Mise-en-place</a>, which already comes pre-installed. On Omarchy, if you press &ldquo;Super+Alt+Space&rdquo; the main menu will open. Pick &ldquo;Install&rdquo; and then &ldquo;Development&rdquo; and you&rsquo;ll see several languages/frameworks you can install, like Ruby on Rails or Go.</p>
<p>But you don&rsquo;t need to use these menus. Let me explain.</p>
<p>On a regular Arch Linux or Ubuntu, an amateur would install ruby or python doing something like this:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code># arch
yay -S ruby python3
# ubuntu
apt install ruby python3</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p><strong>This is the WRONG way.</strong></p>
<p>These commands will install the latest version of each language, and every time you update the system with <code>yay -Syu</code> or <code>apt upgrade</code>, they&rsquo;ll pull in even newer versions.</p>
<p>The thing is, if you develop real projects, <strong>you don&rsquo;t want the versions to change</strong>.</p>
<p>The version deployed on the cloud server and the version on your local machine <strong>MUST BE THE SAME</strong>.</p>
<p>If you&rsquo;re using Ruby v3.0.7 and Node.js 22.19.0, you can&rsquo;t be held hostage to the fact that when you update your system, out of nowhere Ruby 3.4.5 and Node 24.7.0 show up. Everything will start breaking and you&rsquo;ll be super confused without knowing why. This is the most basic mistake a junior developer makes.</p>
<p>To avoid this, every project you&rsquo;re working on MUST BE LOCKED TO FIXED VERSIONS.</p>
<p>The easiest way to do this in 2025 is using <strong>MISE</strong>. As I said, it already comes installed and activated on Omarchy, but if you&rsquo;re using another distro just install Mise manually:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>yay -S mise

# .bashrc
eval $(mise activate bash)</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Adapt this for ZSH, Fish or whatever shell you&rsquo;re using, read the <a href="https://mise.jdx.dev/installing-mise.html"target="_blank" rel="noopener">documentation</a></p>
<p>Now navigate to your project directory, for example:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>cd ~/Projects/AkitaOnRails.com</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>And lock the versions:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>mise use ruby@3.2.3
mise use node@14.21.3</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>This will create a <code>.tool-versions</code> file that you should add to your repository&rsquo;s git:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>❯ cat .tool-versions
ruby 3.2.3
nodejs 14.21.3

❯ git add .tool-versions</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>And done, every time you <code>cd</code> into the directory, Mise will activate exactly the right version for that project. Look:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>AkitaOnRails.com [ master][$!?⇡][ v24.7.0][💎 v3.2.3]
❯ ruby -v
ruby 3.2.3 (2024-01-18 revision 52bb2ac0a6) [x86_64-linux]

AkitaOnRails.com [ master][$!?⇡][ v24.7.0][💎 v3.2.3]
❯ which ruby
/home/akitaonrails/.local/share/mise/installs/ruby/3.2.3/bin/ruby</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Notice that, if you&rsquo;re using the <a href="https://akitaonrails.com/en/2025/09/07/omarchy-2-0-zsh-configs/"target="_blank" rel="noopener">Starship</a> prompt I explained in the previous post, with a preset like Pure Prompt, it shows the version of each language in the prompt so it&rsquo;s easy to see if you&rsquo;re on the wrong version.</p>
<p>In this case, if you read carefully, you&rsquo;ve probably already noticed that <strong>YES, I&rsquo;M ON THE WRONG VERSION</strong> of Node.js. Look how the prompt says I&rsquo;m using Node 24.7.0 but the <code>.tool-versions</code> file asks for 14.21.3.</p>
<p>The reason it&rsquo;s &ldquo;missing&rdquo; is because this machine was recently installed, but the project is old.</p>
<p>So let&rsquo;s check:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>AkitaOnRails.com [ master][$!?⇡][ v24.7.0][💎 v3.2.3]
❯ mise list
Tool    Version            Source                                              Requested
go      1.25.0             ~/.config/mise/config.toml                          latest
node    14.21.3 (missing)  /mnt/data/Projects/AkitaOnRails.com/.tool-versions  14.21.3
node    22.18.0
python  3.13.7
ruby    3.2.3              /mnt/data/Projects/AkitaOnRails.com/.tool-versions  3.2.3
ruby    3.4.5</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>See how in the <code>mise list</code> output it says 14.21.3 is &ldquo;missing&rdquo;. So let&rsquo;s install it:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>AkitaOnRails.com [ master][$!?⇡][ v24.7.0][💎 v3.2.3]
❯ mise use node@14.21.3
mise /mnt/data/Projects/AkitaOnRails.com/.tool-versions tools: node@14.21.3

AkitaOnRails.com [ master][$!?⇡][ v14.21.3][💎 v3.2.3]
❯</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>With the <code>mise use</code> command we can ask it to install and use a particular version. If it&rsquo;s not already installed, it will install it. Notice how after that the Starship prompt changed to reflect that we&rsquo;re now using 14.21.3. That&rsquo;s the right way.</p>
<p>If you&rsquo;re not necessarily in a project directory with locked versions, you can still run commands using a specific version, like this:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>mise exec ruby@3.2.1 -- ruby ...</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Say you want to generate a Rails project on a specific Ruby version:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>mise exec ruby@3.2.3 -- rails new todo-exercise</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>The same goes for generators in Node, like Next.js or any other framework.</p>
<p>I haven&rsquo;t checked whether LazyVim on Omarchy comes configured this way, but in case it doesn&rsquo;t, for NeoVim to support Mise you need to add this:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-lua" data-lang="lua"><span class="line"><span class="cl"><span class="c1">-- Prepend mise shims to PATH</span>
</span></span><span class="line"><span class="cl"><span class="n">vim.env</span><span class="p">.</span><span class="n">PATH</span> <span class="o">=</span> <span class="n">vim.env</span><span class="p">.</span><span class="n">HOME</span> <span class="o">..</span> <span class="s2">&#34;/.local/share/mise/shims:&#34;</span> <span class="o">..</span> <span class="n">vim.env</span><span class="p">.</span><span class="n">PATH</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Just put this in <code>~/.config/nvim/lua/config/mise.lua</code> and it should load the correct path. To integrate with other editors, check <a href="https://mise.jdx.dev/ide-integration.html"target="_blank" rel="noopener">this documentation</a>. There are TONS of advanced options and it&rsquo;s worth reading about them in the <a href="https://mise.jdx.dev/dev-tools/"target="_blank" rel="noopener">Dev-Tools section</a>, but the basics are what I listed here.</p>
<h2>And databases??<span class="hx:absolute hx:-mt-20" id="and-databases"></span>
    <a href="#and-databases" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>The same goes for databases. Every project should be locked to a specific version identical to what&rsquo;s running on the production server and should never depend on operating system packages. You can use mise for this but the most recommended option is to use Docker. Every project <strong>MUST</strong> have a <code>docker-compose.yml</code> to spin up only the databases. You don&rsquo;t need to spin up containers for languages, for that it&rsquo;s better to use Mise.</p>
<p>If you don&rsquo;t understand Docker, I made videos teaching it:</p>


<div class="embed-container">
  <iframe
    src="https://www.youtube.com/embed/85k8se4Zo70"
    title="YouTube video player"
    frameborder="0"
    allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
    referrerpolicy="strict-origin-when-cross-origin"
    allowfullscreen>
  </iframe>
</div>

</br>


<div class="embed-container">
  <iframe
    src="https://www.youtube.com/embed/-yGHG3pnHLg"
    title="YouTube video player"
    frameborder="0"
    allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
    referrerpolicy="strict-origin-when-cross-origin"
    allowfullscreen>
  </iframe>
</div>

<p>Adding up Mise + Docker Compose + LazyVim, that&rsquo;s everything you need to be a productive web developer, while also using your machine&rsquo;s resources efficiently. Every developer NEEDS to learn this combo of options. Omarchy already brings it all pre-installed, which is why it&rsquo;s been my recommendation for every beginner.</p>
<p>Don&rsquo;t worry: Arch Linux (with archinstall) is as easy to install as an Ubuntu or Linux Mint, and Omarchy&rsquo;s Hyprland is much prettier and smoother than MacOS. The best of both worlds. Learn it today!</p>
]]></content:encoded><category>omarchy</category><category>developer-tools</category><category>containers</category></item><item><title>Omarchy 2.0 - LazyVim - LazyExtras</title><link>https://akitaonrails.github.io/en/2025/09/07/omarchy-2-0-lazyvim-lazyextras/</link><guid isPermaLink="true">https://akitaonrails.github.io/en/2025/09/07/omarchy-2-0-lazyvim-lazyextras/</guid><pubDate>Sun, 07 Sep 2025 16:00:00 -0300</pubDate><description>&lt;p&gt;Continuing my series of tips about &lt;a href="https://akitaonrails.com/en/tags/omarchy/"target="_blank" rel="noopener"&gt;Omarchy&lt;/a&gt;, I decided to write about &lt;a href="https://www.lazyvim.org/"target="_blank" rel="noopener"&gt;LazyVim&lt;/a&gt;, which comes pre-installed.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://user-images.githubusercontent.com/292349/213447056-92290767-ea16-430c-8727-ce994c93e9cc.png" alt="LazyVim" loading="lazy" /&gt;&lt;/p&gt;
&lt;p&gt;Even if you don&amp;rsquo;t use Omarchy, I recommend &lt;a href="https://www.lazyvim.org/installation"target="_blank" rel="noopener"&gt;installing&lt;/a&gt; LazyVim. Just do this:&lt;/p&gt;
&lt;div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code"&gt;
&lt;div&gt;&lt;pre&gt;&lt;code&gt;# required
mv ~/.config/nvim{,.bak}
# optional but recommended
mv ~/.local/share/nvim{,.bak}
mv ~/.local/state/nvim{,.bak}
mv ~/.cache/nvim{,.bak}
git clone https://github.com/LazyVim/starter ~/.config/nvim
rm -rf ~/.config/nvim/.git
nvim&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
title="Copy code"
&gt;
&lt;div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;That&amp;rsquo;s it. For those who don&amp;rsquo;t know, NeoVim is a more modern fork of the old Vim (hence the command is &lt;code&gt;nvim&lt;/code&gt;, leaving &lt;code&gt;vim&lt;/code&gt; reserved for the old one). It replaces the old VimScript with Lua scripts and has many optimizations and better quality-of-life features. These days, there&amp;rsquo;s no reason to keep using old Vim.&lt;/p&gt;</description><content:encoded><![CDATA[<p>Continuing my series of tips about <a href="https://akitaonrails.com/en/tags/omarchy/"target="_blank" rel="noopener">Omarchy</a>, I decided to write about <a href="https://www.lazyvim.org/"target="_blank" rel="noopener">LazyVim</a>, which comes pre-installed.</p>
<p><img src="https://user-images.githubusercontent.com/292349/213447056-92290767-ea16-430c-8727-ce994c93e9cc.png" alt="LazyVim"  loading="lazy" /></p>
<p>Even if you don&rsquo;t use Omarchy, I recommend <a href="https://www.lazyvim.org/installation"target="_blank" rel="noopener">installing</a> LazyVim. Just do this:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code># required
mv ~/.config/nvim{,.bak}

# optional but recommended
mv ~/.local/share/nvim{,.bak}
mv ~/.local/state/nvim{,.bak}
mv ~/.cache/nvim{,.bak}

git clone https://github.com/LazyVim/starter ~/.config/nvim

rm -rf ~/.config/nvim/.git

nvim</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>That&rsquo;s it. For those who don&rsquo;t know, NeoVim is a more modern fork of the old Vim (hence the command is <code>nvim</code>, leaving <code>vim</code> reserved for the old one). It replaces the old VimScript with Lua scripts and has many optimizations and better quality-of-life features. These days, there&rsquo;s no reason to keep using old Vim.</p>
<p>Using Lua, you can configure Nvim any way you want. But configuring everything from scratch is a lot of work. It&rsquo;s a good exercise, but practically speaking, it&rsquo;s not worth it day to day. Better to install a pre-configured setup like the old <a href="https://www.lunarvim.org/"target="_blank" rel="noopener">LunarVim</a>, which I used before and even recommended in some Linux videos on my channel, or <a href="https://astronvim.com/"target="_blank" rel="noopener">AstroNvim</a>, or <strong>LazyVim</strong>, which is currently my favorite. Any of them is a good start and it comes down to personal preference.</p>
<p>Each plugin they install has many features and its own key combinations (hotkeys) that you need to read in the documentation to know what does what. I recommend going to the <a href="https://www.lazyvim.org/plugins"target="_blank" rel="noopener">plugins</a> section of the official site and reading them one by one. There&rsquo;s a lot of stuff you wouldn&rsquo;t even expect, and all of it is very useful.</p>
<p>LazyVim on its own already helps a lot because it opens pop-ups documenting some of the hotkeys. For example, what&rsquo;s called the <strong>Leader</strong> command in LazyVim is the &ldquo;space bar&rdquo;. When you press it, this context menu appears:</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/screenshot-2025-09-07_15-44-17.png" alt="Leader context menu"  loading="lazy" /></p>
<p>From here, if you type, say, &ldquo;b&rdquo;, another context menu shows up:</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/screenshot-2025-09-07_15-46-48.png" alt="Buffer context menu"  loading="lazy" /></p>
<p>And if you type &ldquo;b&rdquo; again, it switches to the next file already open in the Buffer. <strong>Buffer</strong> is the Vim name for where already-opened files live. Deleting from the Buffer is the equivalent of &ldquo;closing the file&rdquo;.</p>
<p>Next time, you won&rsquo;t need to look at the menus. Just type quickly in one go: &ldquo;Space+b+b&rdquo;. That&rsquo;s how you memorize the commands you use the most.</p>
<p>Some commands worth learning right away: <strong>Space+Space</strong> (twice), which opens the menu for opening files. Type a few letters of the file name and it filters dynamically:</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/screenshot-2025-09-07_15-49-35.png" alt="find files"  loading="lazy" /></p>
<p>Or &ldquo;Space+e&rdquo; to open the NeoTree Explorer. Type &ldquo;?&rdquo; to open a popup with the commands you can use to create new subdirectories or files within the subdirectory:</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/screenshot-2025-09-07_15-51-08.png" alt="NeoTree"  loading="lazy" /></p>
<p>Once you learn the other commands and plugins, you&rsquo;ll notice you don&rsquo;t even need to open NeoTree. It&rsquo;s more for when you want to explore visually. For day-to-day work, commands like &ldquo;:e&rdquo; should be enough. By the way, &ldquo;:&rdquo; (colon) is the command for executing NeoVim functions. For example &ldquo;:q&rdquo; is quit, &ldquo;:w&rdquo; is write, and &ldquo;:wq&rdquo; is write and quit at the same time.</p>
<p>If you want to learn NeoVim more deeply, I recommend the YouTube channel of my friend <a href="https://www.youtube.com/@EustaquioRangel"target="_blank" rel="noopener">Eustáquio Rangel</a>, a Linux, Rails, and Vim veteran who teaches NeoVim from scratch (without LazyVim).</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/screenshot-2025-09-07_16-09-53.png" alt="TaQ"  loading="lazy" /></p>
<p>Now, let&rsquo;s say you&rsquo;ve already learned the basics of NeoVim and LazyVim, and now you want to start working on your PHP, Java, C#, Ruby, Python, or whatever projects. You&rsquo;ll notice that LazyVim doesn&rsquo;t have any functionality for any of them.</p>
<p>What do you do now? Install VS Code?? <strong>NO!!</strong></p>
<p>That&rsquo;s because you haven&rsquo;t run <a href="https://www.lazyvim.org/extras"target="_blank" rel="noopener">:LazyExtras</a> yet.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/screenshot-2025-09-07_15-35-36.png" alt="LazyExtras command"  loading="lazy" /></p>
<p>Type it exactly like that and watch this:</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/screenshot-2025-09-07_15-36-01.png" alt="Enabled Plugins"  loading="lazy" /></p>
<p>This window looks complicated but it&rsquo;s just a list of plugins split into sections. At the top you see the plugins already installed and enabled. If you don&rsquo;t want any of them, just use the arrows to move the cursor down to one of them and press &ldquo;x&rdquo; to unmark it. But leave that section as is. Let&rsquo;s scroll down to the &ldquo;Languages&rdquo; section:</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/screenshot-2025-09-07_15-36-43.png" alt="Languages section"  loading="lazy" /></p>
<p>This is the section where all the languages you can enable support for live. Just scroll down with the arrows and mark with &ldquo;x&rdquo; which ones you want to install. And there&rsquo;s everything: Angular, Vue, Erlang, Elixir, Rust, Zig, Haskell, and much more.</p>
<p>Next to each language is the group of individual plugins it will install. To know what each one does, type their names into Google and find the documentation page, where you&rsquo;ll find hotkeys and extra configurations you can set.</p>
<p>With this you gain things like Linters, syntax highlighting, LSP, snippets, and much more.</p>
<p>And if you want to install additional plugins that aren&rsquo;t listed, you can add them manually. Read the <a href="https://www.lazyvim.org/configuration/plugins#-adding-plugins"target="_blank" rel="noopener">Adding Plugins</a> section in the documentation.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/screenshot-2025-09-07_16-05-15.png" alt="Linter"  loading="lazy" /></p>
<p>LazyVim + LazyExtras covers 90% of everything you need for day-to-day software development. It&rsquo;s lighter and faster than VS Code, uses way less memory, and will be much better especially on older machines. Don&rsquo;t be lazy about learning Vim. A real programmer shouldn&rsquo;t stick with VS Code just because they&rsquo;re too lazy to learn a few extra hotkeys.</p>
]]></content:encoded><category>omarchy</category><category>developer-tools</category><category>tutorials</category></item><item><title>Omarchy 2.0 - ZSH Configs</title><link>https://akitaonrails.github.io/en/2025/09/07/omarchy-2-0-zsh-configs/</link><guid isPermaLink="true">https://akitaonrails.github.io/en/2025/09/07/omarchy-2-0-zsh-configs/</guid><pubDate>Sun, 07 Sep 2025 15:00:00 -0300</pubDate><description>&lt;p&gt;I&amp;rsquo;ve been really enjoying &lt;a href="https://omarchy.org/"target="_blank" rel="noopener"&gt;Omarchy&lt;/a&gt; as my desktop manager. Read &lt;a href="https://akitaonrails.com/en/2025/08/29/new-omarchy-2-0-install/"target="_blank" rel="noopener"&gt;my previous post&lt;/a&gt; to see how I installed it and tweaked it for my setup. Following that thread, Omarchy ships with Bash as the default shell. I prefer ZSH. Bash is perfectly usable, this is just personal preference. Some people prefer Fish or others. But Omarchy only ships with Bash for now, so I decided to modify the setup to support my ZSH.&lt;/p&gt;</description><content:encoded><![CDATA[<p>I&rsquo;ve been really enjoying <a href="https://omarchy.org/"target="_blank" rel="noopener">Omarchy</a> as my desktop manager. Read <a href="https://akitaonrails.com/en/2025/08/29/new-omarchy-2-0-install/"target="_blank" rel="noopener">my previous post</a> to see how I installed it and tweaked it for my setup. Following that thread, Omarchy ships with Bash as the default shell. I prefer ZSH. Bash is perfectly usable, this is just personal preference. Some people prefer Fish or others. But Omarchy only ships with Bash for now, so I decided to modify the setup to support my ZSH.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/screenshot-2025-09-07_15-16-57.png" alt="My ZSH"  loading="lazy" /></p>
<p>If you want to switch to ZSH, it&rsquo;s easy, just do this:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">yay -S zsh zoxide
</span></span><span class="line"><span class="cl">chsh -s <span class="k">$(</span>which zsh<span class="k">)</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Logout, login, and done. But now your shell will be empty. To grab my config do this:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">git clone https://github.com/akitaonrails/omarchy-zsh.git ~/.config/zsh
</span></span><span class="line"><span class="cl">ln -s ~/.config/zsh/.zshrc ~/.zshrc </span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>There are two things you need to change. In <code>.zshrc</code> remove this line:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>source ~/.config/zsh/mounts</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>That&rsquo;s just for me to check my NFS mounts to my NAS. It&rsquo;s useless to you so you can remove it.</p>
<p>The second thing is to create a new file for secrets:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>touch ~/.config/zsh/secrets
chmod 600 ~/.config/zsh/secrets</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>This is where you put stuff like your OpenAI or Google Cloud keys or anything like that. For example:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code># ~/.config/zsh/secrets
export OPENAI_API_KEY=&#34;sk-xx-v1-xxx...xxxxx&#34;</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>That way your secrets stay separated from your configs and we can <code>git push</code> to a repository without worrying that something might leak in the future. Always keep secrets, passwords, and keys separated locally. This is already in <code>.gitignore</code> so you&rsquo;re safe.</p>
<p>As a bonus, in <code>~/.config/init</code> I added support for <a href="https://atuin.sh/"target="_blank" rel="noopener">Atuin</a>, a tool that syncs all the command history you ran in your shell to a &ldquo;cloud&rdquo; repository (read the docs, you can create your own local server too). The repository is encrypted, so it&rsquo;s safe even if your history contains secret keys in the commands.</p>
<p>Install it like this:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>yay -S atuin
atuin register -u &lt;your username&gt; -e &lt;your email&gt;
atuin import auto
atuin sync</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>As soon as you register, Atuin will generate a random encryption key. Make sure you store this key somewhere safe like 1Password, Bitwarden or another secure vault!! Without it you won&rsquo;t be able to decrypt on a new installation. If you forget, you can still view it before reinstalling, like:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>atuin key</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>If you reinstall your machine or set up a new one and want your history back, just install Atuin and run:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>atuin login -u &lt;your username&gt;
atuin sync</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>It will ask for your password and encryption key and bring all your history back.</p>
<p>With my config, just hit <code>Ctrl+R</code> to bring up the history search (which from now on will live in a sqlite on your machine). Read the <a href="https://docs.atuin.sh/"target="_blank" rel="noopener">documentation</a> for more features.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/screenshot-2025-09-07_15-17-20.png" alt="Ctrl&#43;R"  loading="lazy" /></p>
<p>DHH set up the <strong>Starship</strong> prompt using the old <code>PS1</code> variable style. But Starship already has several nice prompts that are easy to use as &ldquo;presets&rdquo;. I picked Pure Prompt, which I like, but there are plenty of others. If you want something flashier and more colorful, there&rsquo;s this <a href="https://starship.rs/presets/pastel-powerline"target="_blank" rel="noopener">Pastel Powerline</a>:</p>
<p><img src="https://starship.rs/presets/img/pastel-powerline.png" alt="Pastel Powerline"  loading="lazy" />
Pick your favorite on the <a href="https://starship.rs/presets/"target="_blank" rel="noopener">Presets page</a> and change <code>~/.config/zsh/prompt</code> on this line:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>starship preset bracketed-segments -o ~/.config/starship.toml</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Finally, I left some ENVs in <code>~/.config/zsh/envs</code> that work for my Ollama tests and things like that, but it&rsquo;s good for you to know they&rsquo;re there so you don&rsquo;t find it weird if your Ollama is behaving strangely. Edit the <code>~/.config/zsh/envs</code> file to set the envs you prefer:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code># envs
export OPENAI_API_BASE=&#34;https://openrouter.ai/api/v1&#34;
export DEFAULT_MODEL=&#34;o1-mini&#34;;
export OLLAMA_API_BASE=http://127.0.0.1:11434
export OLLAMA_HOME=http://127.0.0.1:11434
export OLLAMA_MODELS=/mnt/gigachad/ollama/models</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Also modify the <code>~/.config/zsh/aliases</code> file to include aliases you prefer:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code># aliases
alias monhd=&#34;sudo ddcutil -d 1 setvcp 60 0x12&#34;
alias mondp=&#34;sudo ddcutil -d 1 setvcp 60 0x0F&#34;

alias sgpt=&#39;docker run --rm -e OPENAI_API_BASE=${OPENAI_API_BASE} -e OPENAI_API_KEY=${OPENROUTER_API_KEY} ghcr.io/tbckr/sgpt:latest txt &#39;

alias git=&#39;nocorrect git&#39;
git config --global alias.a &#39;add&#39;
git config --global alias.ps &#39;push&#39;
git config --global alias.pl &#39;pull&#39;
git config --global alias.l &#39;log&#39;
git config --global alias.c &#39;commit -m&#39;
git config --global alias.s &#39;status&#39;
git config --global alias.co &#39;checkout&#39;
git config --global alias.b &#39;branch&#39;</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>The first two aliases are for my dual monitor setup where one of the monitors receives signal from both the HDMI input and the DisplayPort input (I have 2 GPUs). If you didn&rsquo;t know, you can control that from the shell. Read <a href="https://jeancharles.quillet.org/posts/2021-08-20-How-to-use-ddcutil-to-switch-input-of-a-Dell-screen.html"target="_blank" rel="noopener">this post about ddcutil</a></p>
<p>Next you get the <code>sgpt</code> command. Omarchy already ships with Docker installed. Now from the shell you can ask ChatGPT without having to open a web browser for it:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>sgpt &#34;what is the rsync syntax to sync two directories?&#34;</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Read the <a href="https://github.com/tbckr/sgpt"target="_blank" rel="noopener">SGPT documentation</a> to learn about other features or which LLMs you can choose.</p>
<p>At the end we have aliases for Git. Omarchy already has an alias making &ldquo;g&rdquo; mean &ldquo;git&rdquo; and with this one I added you can do:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>git add . # old
g a . # new

git commit -m &#34;initial commit&#34; # old
g c &#34;initial commit&#34; # new

git commit --amend -m &#34;initial commit&#34;
g ca &#34;initial commit&#34;

git push origin master
g ps origin master

git pull origin master
g pl origin master

git log
g l

# and so on</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>More practical and less verbose. Add more aliases as your workflow demands in <code>~/.config/aliases</code>.</p>
<p>And I think that&rsquo;s it, now my Omarchy is organized the way I like. Make your own tweaks so everything fits your style too!</p>
]]></content:encoded><category>omarchy</category><category>developer-tools</category><category>automation</category></item><item><title>Running Arch Linux over Windows 10!</title><link>https://akitaonrails.github.io/en/2018/04/29/running-arch-linux-over-windows-10/</link><guid isPermaLink="true">https://akitaonrails.github.io/en/2018/04/29/running-arch-linux-over-windows-10/</guid><pubDate>Sun, 29 Apr 2018 22:06:00 -0300</pubDate><description>&lt;p&gt;Ok, anyone that has been reading my blog for the past year or two knows how I &lt;a href="http://www.akitaonrails.com/archlinux"target="_blank" rel="noopener"&gt;enjoy Arch Linux&lt;/a&gt; (in particular Manjaro Gnome).&lt;/p&gt;
&lt;p&gt;I am also still very much intrigued by the idea of Windows Subsystem for Linux (or WSL) which properly debuted in the &lt;a href="http://www.akitaonrails.com/en/2016/07/26/o-ano-do-linux-no-desktop-esta-usavel"target="_blank" rel="noopener"&gt;Windows 10 Anniversary Edition&lt;/a&gt; back in mid-2016.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s been almost 2 years and we&amp;rsquo;re expecting some significant updates to WSL compatibility and performance for the next &lt;a href="https://winaero.com/blog/command-line-wsl-improvements-windows-10-version-1803/"target="_blank" rel="noopener"&gt;Spring Creators Update&lt;/a&gt; (or version 1803) scheduled to arrive on April 30, 2018. This brings it closer to making WSL actually usable for professional programmers. Just to give you an idea, right now you will have orders of magnitude better performance if you run your favorite Linux distro inside Virtualbox or VMWare Workstation.&lt;/p&gt;</description><content:encoded><![CDATA[<p>Ok, anyone that has been reading my blog for the past year or two knows how I <a href="http://www.akitaonrails.com/archlinux"target="_blank" rel="noopener">enjoy Arch Linux</a> (in particular Manjaro Gnome).</p>
<p>I am also still very much intrigued by the idea of Windows Subsystem for Linux (or WSL) which properly debuted in the <a href="http://www.akitaonrails.com/en/2016/07/26/o-ano-do-linux-no-desktop-esta-usavel"target="_blank" rel="noopener">Windows 10 Anniversary Edition</a> back in mid-2016.</p>
<p>It&rsquo;s been almost 2 years and we&rsquo;re expecting some significant updates to WSL compatibility and performance for the next <a href="https://winaero.com/blog/command-line-wsl-improvements-windows-10-version-1803/"target="_blank" rel="noopener">Spring Creators Update</a> (or version 1803) scheduled to arrive on April 30, 2018. This brings it closer to making WSL actually usable for professional programmers. Just to give you an idea, right now you will have orders of magnitude better performance if you run your favorite Linux distro inside Virtualbox or VMWare Workstation.</p>
<p>Moreover, out of the box the &ldquo;Bash for Windows&rdquo; proper only officially supports Ubuntu, Fedora, and OpenSuse I guess. Most people will just install Ubuntu. And it works ok. For toy and cool demonstration purposes, it works. But it really frustrates me that I can do so much but I can&rsquo;t actually use it as my daily driver. It&rsquo;s like being able to carry the fully built prototype of the next iPhone but no 4G support yet. So it&rsquo;s just a toy.</p>
<p>Bear with me here, if you just want to see how the performance compares to my VMWare setup, go straight to the end of the article.</p>
<p>Anyway, in the case of distros. Serious Linux users would prefer better alternatives. Enter this GitHub repository:</p>
<p><a href="https://github.com/yuk7/ArchWSL"target="_blank" rel="noopener"><img src="http://web.archive.org/web/20221226012212/https://raw.githubusercontent.com/wiki/yuk7/WSL-DistroLauncher/img/Arch_Alpine_Ubuntu.png" alt="screenfetch of arch"  loading="lazy" /></a></p>
<p>You just download <a href="https://github.com/yuk7/ArchWSL/releases/latest"target="_blank" rel="noopener">this zip file</a>, unzip it and run the included <code>Arch.exe</code>. And that&rsquo;s about it!</p>
<p>Now, you can go ahead and open the Windows version of &ldquo;Bash&rdquo; and we can bootstrap the rest of the installation setup from there.</p>
<p>We must get Pacman and some AUR manager. To start Pacman, we must do this:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>pacman-key --init
pacman-key --populate
pacman -Syu</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Hell yeah, Pacman running natively on Windows!! Who would&rsquo;ve known??</p>
<p><img src="https://akitaonrails.s3.amazonaws.com/assets/image_asset/image/674/big_IMG_20180429_174518.jpg" alt="pacman on windows"  loading="lazy" /></p>
<p>This will bring everything up to date. Next up, we must create a non-root user:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>useradd -m your_user
passwd your_user
EDITOR=nano visudo</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Look for the line that says <code>root   ALL=(ALL) ALL</code> and add your user right on the next line like this:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>your_user   ALL=(ALL) ALL</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Finally, we should login as this user:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>su your_user</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Next up, let&rsquo;s install Yaourt so we can use it to install Pacaur (this is a personal preference, you can just use Yaourt. I think Yaourt prompts too much, that&rsquo;s why I prefer Pacaur).</p>
<p>Start by editing your <code>/etc/pacman.conf</code> file with your favorite editor like vim or nano.</p>
<p>Just add the following section to the very bottom of the file:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>[archlinuxfr]
SigLevel = Never
Server = http://repo.archlinux.fr/$arch</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Before we can proceed, we have one small problem. WSL still has no support for SYSV IPC. This is required for <a href="https://unix.stackexchange.com/questions/9714/what-is-the-need-for-fakeroot-command-in-linux"target="_blank" rel="noopener">fakeroot</a>, which is required by <code>makepkg</code> (which cannot run as root).</p>
<p>To overcome this problem, this is what we&rsquo;ll have to do:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>wget https://github.com/yuk7/arch-prebuilt/releases/download/17121600/fakeroot-tcp-1.22-1-x86_64.pkg.tar.xz
sudo pacman -U fakeroot-tcp-1.22-1-x86_64.pkg.tar.xz</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>And that&rsquo;s it for now! Until WSL adds proper support for SYSV IPC, we can use this. Yaourt itself will probably prompt you to install <code>fakeroot-tcp</code> on top of it, just let it.</p>
<p>As I said, Yaourt is quite verbose in its many prompts for confirmations. Rule of thumb, whenever it prompts if you want to edit anything, just say &ldquo;N&rdquo;(o). Whenever it prompts you if you want to build or install something, just say &ldquo;Y&rdquo;(es). If you got annoyed with me, do this:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>yaourt -S pacaur</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>From now on, I will assume you have Pacaur.</p>
<h3>Graphical User Interface Support<span class="hx:absolute hx:-mt-20" id="graphical-user-interface-support"></span>
    <a href="#graphical-user-interface-support" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Now, let&rsquo;s install some of the basics for a development environment:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>sudo pacman -S base base-devel gvim git</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>It will prompt you sometimes &ldquo;default: all&rdquo;, just install everything. Hard disk space should not be a concern in 2018.</p>
<p>I prefer to have a full-on GNOME 3 environment, so I just do:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>sudo pacman -S gnome</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Again, let it install everything it wants. Everybody has a different taste when it comes to GUIs, some prefer KDE5, others prefer XFCE4. Some even go as far as using the tile-based GUI <a href="https://i3wm.org/"target="_blank" rel="noopener">i3</a>.</p>
<p>That requires some serious adapting. It&rsquo;s for people that like to do stuff like using a tenkeyless keyboard with nothing written in the keycaps and using an alien layout like  DVORAK or <a href="https://colemak.com/"target="_blank" rel="noopener">Colemak</a> (yikes!). Taste is taste. And I dare you to become a touch typist using <a href="https://www.maltron.com/the-maltron-letter-layout-advantage.html"target="_blank" rel="noopener">Maltron</a>, I double dare ya! :-D</p>
<p>But, I digress. Now, you can add this to your <code>/etc/.bashrc</code> file or the global <code>/etc/environment</code> file:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>echo &#34;export LIBGL_ALWAYS_INDIRECT=1&#34; &gt;&gt; /etc/.bashrc
echo &#34;export DISPLAY=:0&#34; &gt;&gt; /etc/.bashrc</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Export those to your current shell, or just close and reopen Bash.</p>
<p>We can have a full GUI environment by installing a local X Server. You have 2 options, Xming and VcXSrv. I am having trouble resizing windows in Xming, so I am recommending <a href="https://sourceforge.net/projects/vcxsrv/"target="_blank" rel="noopener">VcXSrv</a> instead. Just download and install it as you would with any Windows application and start it up. It will add a Desktop shortcut named &ldquo;XLaunch&rdquo;, just fire it up.</p>
<p>And finally, we can install a <strong>PROPER</strong> usable terminal instead of that poor contraption derived from old cmd.exe that WSL provides you out of the box.</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>pacaur -S tilix-bin
tilix</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>If you&rsquo;ve been a Mac user, you probably know iTerm2, which is possibly the best Terminal emulator I&rsquo;ve ever used. There is nothing else that comes close. Nothing, except possibly <a href="https://gnunn1.github.io/tilix-web/"target="_blank" rel="noopener">Tilix</a> (previously known as Terminix).</p>
<p>Just for having &ldquo;Ctrl-Alt-D&rdquo; to split the terminal horizontally down and &ldquo;Ctrl-Alt-R&rdquo; to split it vertically to the right, and using &ldquo;Alt-1&rdquo;, &ldquo;Alt-2&rdquo;, and so on to switch between the terminals, it&rsquo;s great for me. It also comes pre-installed with very nice themes such as the now classic Solarized Dark or my current favorite Monokai Dark.</p>
<p>Don&rsquo;t curse me, I know. Some will prefer the default terminal app and just add TMUX. Again, taste (it&rsquo;s more useful if I were working on a remote server).</p>
<p>Add the Hack monotype font to make everything more pleasing to the eye:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>sudo pacman -S ttf-hack</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<h3>Programming Languages<span class="hx:absolute hx:-mt-20" id="programming-languages"></span>
    <a href="#programming-languages" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Let&rsquo;s see if the most important languages out there install correctly. As I always say, look no further than ASDF for that task.</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>git clone https://github.com/asdf-vm/asdf.git ~/.asdf --branch v0.4.3
echo -e &#39;\n. $HOME/.asdf/asdf.sh&#39; &gt;&gt; ~/.bashrc
echo -e &#39;\n. $HOME/.asdf/completions/asdf.bash&#39; &gt;&gt; ~/.bashrc</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Restart your terminal and continue:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>asdf plugin-add nodejs
addf plugin-add ruby</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>For Node.js you must add the proper GPG keys and only then you can install:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>bash ~/.asdf/plugins/nodejs/bin/import-release-team-keyring
asdf install nodejs 10.0.0
asdf global nodejs 10.0.0</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Ruby benefits from jemalloc to allocate less system memory. I have no idea if it impacts WSL but let&rsquo;s do it anyway:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>sudo pacman -S jemalloc
RUBY_EXTRA_CONFIGURE_OPTIONS=&#34;--with-jemalloc&#34; asdf install ruby 2.5.1
asdf global ruby 2.5.1
gem install bundler</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p><img src="https://akitaonrails.s3.amazonaws.com/assets/image_asset/image/675/big_IMG_20180429_193432.jpg" alt="ruby compiles"  loading="lazy" /></p>
<p>So far so good, if you need to install an old Ruby (&lt; 2.4) for legacy projects, you must do:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>pacaur -S openssl-1.0
PKG_CONFIG_PATH=/usr/lib/openssl-1.0/pkgconfig RUBY_EXTRA_CONFIGURE_OPTIONS=&#34;--with-openssl-dir=/usr/lib/openssl-1.0&#34; asdf install ruby 2.3.3</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Unfortunately it needs a version of OpenSSL that you should not be using due to security problems. We all moved on to 1.1. But Ruby 2.3.x reached its EOL (end of line). So it&rsquo;s at your own risk to keep using it.</p>
<p>Well, so far so good. Can we install Go as well? Let&rsquo;s see:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>asdf plugin-add golang
asdf install golang 1.9.5
asdf global goland 1.9.5</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>We can keep going, but I think you got the idea. It just works!</p>
<h3>Background Jobs<span class="hx:absolute hx:-mt-20" id="background-jobs"></span>
    <a href="#background-jobs" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Again, another current limitation of WSL (that we expect to see fixed on the Spring Creators Update) is the ability to start and keep running background jobs (daemons).</p>
<p>Just doing <code>sudo systemctl enable postgresql</code> and restarting won&rsquo;t automatically start Postgresql in the background as it should. This Arch.exe thing we&rsquo;re using won&rsquo;t even have systemd.</p>
<p>Fortunately, servers such as Postgresql or Redis do work normally, they can be started as user-level processes, and they do properly bind to their respective TCP ports. But, you will have to manually start them in every session. Close your Bash terminal and they are all killed off.</p>
<p>For example, Postgresql:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>[your_user]# sudo pacman -S postgresql
[your_user]# sudo mkdir -p /run/postgresql
[your_user]# sudo chown -R postgres:postgres /run/postgresql

[your_user]# sudo -u postgres -i
[postgresql]# initdb --locale $LANG -E UTF8 -D &#39;/var/lib/postgres/data&#39;

[postgresql]# pg_ctl -D /var/lib/postgres/data start
waiting for server to start....2018-04-29 23:30:35.483 UTC [1064] LOG:  listening on IPv4 address &#34;127.0.0.1&#34;, port 5432
2018-04-29 23:30:35.505 UTC [1064] LOG:  listening on Unix socket &#34;/run/postgresql/.s.PGSQL.5432&#34;
2018-04-29 23:30:35.583 UTC [1065] LOG:  database system was shut down at 2018-04-29 23:23:48 UTC
2018-04-29 23:30:35.660 UTC [1064] LOG:  database system is ready to accept connections

[postgresql]# createuser --interactive
Enter name of role to add: your_user
Shall the new role be a superuser? (y/n) y

[postgresql]# exit
[your_user]#</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>See what I did here? There is a small problem in the install under WSL where the <code>/run/postgresql</code> is not created with the correct permissions. Fixing that we can start the server. We can exit out of the <code>su</code> session and the postgresql server will keep running. But when we close the first Bash window/session, it will die.</p>
<p>And another very annoying thing? The <code>mkdir</code> and <code>chown</code> fixes above? I have to do it every single time I close the Bash for Windows app and start it again!! Super duper annoying if you ask me!</p>
<p>But, we can live with it for now. Hopefully, this will be fixed tomorrow (April 30) or in an upcoming upgrade.</p>
<p>In a Rails development environment, we can take advantage of <a href="https://github.com/theforeman/foreman"target="_blank" rel="noopener">Foreman</a> to help us out. Just edit some <code>Procfile.dev</code> file:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>web: bundle exec puma -C config/puma.rb -p 3000
db: su postgres -c &#39;pg_ctl start -D /var/lib/postgres/data&#39;
redis: redis-server /usr/local/etc/redis.conf
mailcatcher: mailcatcher -f</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Now we can do: <code>foreman start -f Procfile.dev</code> and all services will start properly at once.</p>
<h3>Real World Performance<span class="hx:absolute hx:-mt-20" id="real-world-performance"></span>
    <a href="#real-world-performance" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>My daily driver is Manjaro GNOME under VMWare Workstation Pro on my Surface Book 2. I give it 6 threads out of the 8 and a hefty 12GB of RAM out of the total 16GB (damn Microsoft, we need more RAM nowadays that the cool kids deploy stupid ass Apps with heavy JS/CSS coating that eats up all available RAM).</p>
<p>In the project I am currently working on, my full RSpec suite is a bit on the slow side. For this comparison, I am skipping all my feature specs as I am in no mood to tweak chrome-driver to work in WSL (probably runs, but let&rsquo;s have it another day).</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>Finished in 12 minutes 8 seconds (files took 14.58 seconds to load)
1493 examples, 0 failures, 35 pending

531,34s user 127,56s system 88% cpu 12:24,99 total</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>In this comparable WSL environment I have just installed, I am running the exact same RSpec suite, and this is what I get:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>Finished in 13 minutes 43 seconds (files took 3 minutes 16.8 seconds to load)
1474 examples, 0 failures, 35 pending


455.80s user 399.14s system 83% cpu 17:04.96 total</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>For some reason, my WSL environment is skipping a few examples (seems more like an RSpec counter bug of some sort though), but I think this shouldn&rsquo;t pose too much of a difference in the grand scheme of things here. WSL is losing even if the counter is correct and it&rsquo;s running fewer examples.</p>
<p>When we start to really exercise the WSL a whole lot of issues start to show up. For example, PostgreSQL goes crazy and keeps stdout&rsquo;ing &ldquo;could not flush dirty data: Function not implemented&rdquo;, which is due to <a href="https://github.com/Microsoft/WSL/issues/645"target="_blank" rel="noopener">this documented issue</a> from the WSL! So what ends up happening is that sometimes the RSpec runner just pauses while PG tries to figure out what to do.</p>
<p>You can clearly see that under VMWare files took less than 15 seconds to load. On WSL they took over 3 minutes just on file I/O! It&rsquo;s orders of magnitude slower. This is the bad part. When it&rsquo;s just CPU vs CPU, they are pretty comparable actually.</p>
<p>On paper, the total time is actually quite close. And CPU-wise I think WSL has an edge, which is why it&rsquo;s able to recover in the totals even though the I/O is clearly sluggish.</p>
<p>In practice what happens in a normal programming situation is that you fire up Vim, or any other text editor of your choice. Any programmer has to keep opening files and going back and forth between a lot of files. Now, I/O being super slow, every file you try to open pauses your action for a split second. And this adds up.</p>
<p>Within VMWare, Vim is super responsive, whenever I need to open a file, it&rsquo;s almost instantaneous.</p>
<p>The benchmark may be hard to account for this situation. But in a normal scenario, you will end up annoyed. Moreover, running a GUI over X (VcXsrv in my case) slows things down a bit as well. From within VMWare, the normal Xorg can take advantage of being GPU accelerated. So the entire rasterization pipeline is faster.</p>
<p>You &ldquo;can&rdquo; use WSL as your daily driver. But if I can have a smoother experience from within VMWare, that&rsquo;s where I will be for now.</p>
<h3>Conclusion<span class="hx:absolute hx:-mt-20" id="conclusion"></span>
    <a href="#conclusion" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>I will actually hold my conclusions until tomorrow (April 30) or later this week, because if the Spring Creators Update actually fixes some performance issues, then I can see myself using this instead of my VMWare Workstation install of Manjaro GNOME.</p>
<p>It may not come in this big update, but I have word that they are working on the outstanding I/O performance issues. So it&rsquo;s right around the corner.</p>
<p>Everything I need just works. Tilix, Vim, Git, Zsh, Ruby, Node.js. Everything installs as expected from Pacman and AUR. Pure Arch Linux glory! So sad the bad performance spoils it.</p>
<p>It&rsquo;s close, it&rsquo;s very close! For the first time in almost 15 years, I can almost see myself returning to 100% Windows (with no VMWare support) and still be able to be fully productive with real, professional, open source tools that &ldquo;Just Works&rdquo;.</p>
<p>Keep an eye on this blog post for updates this week!</p>
]]></content:encoded><category>linux</category><category>microsoft</category><category>developer-tools</category></item><item><title>Replacing RVM/Rbenv/Nvm/etc for ASDF</title><link>https://akitaonrails.github.io/en/2017/10/24/replacing-rvm-rbenv-nvm-etc-for-asdf/</link><guid isPermaLink="true">https://akitaonrails.github.io/en/2017/10/24/replacing-rvm-rbenv-nvm-etc-for-asdf/</guid><pubDate>Tue, 24 Oct 2017 14:19:00 -0200</pubDate><description>&lt;p&gt;Many people are using Docker as the means to have different Ruby versions or for any other language. I still think the added overhead both in resources usage and usability friction is simply not worth it. I highly recommend against it. Docker is great as the basis for automated infrastructures, but I prefer to have them in servers only.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve been using &lt;a href="https://github.com/asdf-vm/asdf"target="_blank" rel="noopener"&gt;asdf&lt;/a&gt; as my main Ruby version manager for a long while now and I am confident that I can recommend it in place of the more well recognized RVM or Rbenv.&lt;/p&gt;</description><content:encoded><![CDATA[<p>Many people are using Docker as the means to have different Ruby versions or for any other language. I still think the added overhead both in resources usage and usability friction is simply not worth it. I highly recommend against it. Docker is great as the basis for automated infrastructures, but I prefer to have them in servers only.</p>
<p>I&rsquo;ve been using <a href="https://github.com/asdf-vm/asdf"target="_blank" rel="noopener">asdf</a> as my main Ruby version manager for a long while now and I am confident that I can recommend it in place of the more well recognized RVM or Rbenv.</p>
<p>Moreover, it not only can manage Ruby versions, but it can manage almost all languages you might want. With just one command set. So you don&rsquo;t even need virtualenv for Python or NVM for Node.js. Just use ASDF.</p>
<p>Installing it couldn&rsquo;t be easier. Just follow the <a href="https://github.com/asdf-vm/asdf/blob/master/README.md"target="_blank" rel="noopener">README</a> from the project page.</p>
<p>Don&rsquo;t forget to install the base development tools for your environment. You can follow <a href="https://github.com/rbenv/ruby-build/wiki"target="_blank" rel="noopener">ruby-build&rsquo;s wiki page</a> for example:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>## For OS X
# optional, but recommended:
brew install openssl libyaml libffi

# required for building Ruby &lt;= 1.9.3-p0:
brew tap homebrew/dupes &amp;&amp; brew install apple-gcc42

## For Ubuntu
sudo apt-get install gcc-6 autoconf bison build-essential libssl-dev libyaml-dev libreadline6-dev zlib1g-dev libncurses5-dev libffi-dev libgdbm3 libgdbm-dev

## For Arch
sudo pacman -S --needed gcc5 base-devel libffi libyaml openssl zlib</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Then you can install ASDF itself:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>git clone https://github.com/asdf-vm/asdf.git ~/.asdf --branch v0.4.0</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Then add the proper environment configuration for Path and auto-completion.</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code># For Ubuntu or other linux distros
echo -e &#39;\n. $HOME/.asdf/asdf.sh&#39; &gt;&gt; ~/.bashrc
echo -e &#39;\n. $HOME/.asdf/completions/asdf.bash&#39; &gt;&gt; ~/.bashrc

# OR for Mac OSX
echo -e &#39;\n. $HOME/.asdf/asdf.sh&#39; &gt;&gt; ~/.bash_profile
echo -e &#39;\n. $HOME/.asdf/completions/asdf.bash&#39; &gt;&gt; ~/.bash_profile</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Finally, you must install one of the dozens of <a href="https://github.com/asdf-vm/asdf-plugins"target="_blank" rel="noopener">plugins</a>. In my case, I have these installed:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>asdf plugin-add clojure https://github.com/vic/asdf-clojure.git
asdf plugin-add elixir https://github.com/asdf-vm/asdf-elixir.git
asdf plugin-add erlang https://github.com/asdf-vm/asdf-erlang.git
asdf plugin-add golang https://github.com/kennyp/asdf-golang.git
asdf plugin-add python https://github.com/tuvistavie/asdf-python.git
asdf plugin-add ruby https://github.com/asdf-vm/asdf-ruby.git

# Imports Node.js release team&#39;s OpenPGP keys to main keyring
bash ~/.asdf/plugins/nodejs/bin/import-release-team-keyring

asdf plugin-add nodejs https://github.com/asdf-vm/asdf-nodejs.git</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>You can update the plugins all at once with this simple command:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>asdf plugin-update --all</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>You can see what versions are available for a particular language like this:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>asdf list-all ruby
asdf list-all clojure
asdf list-all python</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Then you can install any version you need like this:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>asdf install ruby 2.4.2
asdf install nodejs 8.7.0
asdf install erlang 20.1</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>After you install a particular language version, I always set one as the system default like this:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>asdf global ruby 2.4.2
asdf global elixir 1.5.2</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>And in a particular project directory, I can set it to use any other version, just for that project:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>asdf local ruby 2.3.4</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>The command above will write a <code>.tool-versions</code> file to the directory you&rsquo;re at when you ran it. It will contain the language and version you chose, so whenever you go back to that directory ASDF will set the correct version for the language you need. The previous <code>asdf global &lt;language&gt;</code> command is actually writing a <code>.tool-versions</code> file to your home directory. The local config overrides the home directory version.</p>
<p>Another important thing to remember, whenever you install libraries which have executable scripts that need to be in the PATH, you must <strong>reshim</strong> them. For example:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>npm install -g phantomjs # will install phantomjs
asdf reshim nodejs # will put the shim for the phantomjs executable in the PATH
phantomjs # will properly execute it</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>If you try to install Ruby versions prior to 2.4 you will find <a href="https://github.com/asdf-vm/asdf-ruby/wiki/Ruby-Installation-Problems"target="_blank" rel="noopener">compilation problems</a> as it depends on gcc5 and openssl-1.0. So you should use the following command (assuming you have already installed the obsolete openssl-1.0 and gcc5):</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>CC=gcc-5 PKG_CONFIG_PATH=/usr/lib/openssl-1.0/pkgconfig \
RUBY_EXTRA_CONFIGURE_OPTIONS=&#34;--with-openssl-dir=/usr/lib/openssl-1.0&#34; \
asdf install ruby 2.3.4</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Sometimes, if a dependency is missing and an install fails, you must manually remove it before attempting to reinstall, so you have to do:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>asdf remove &lt;language&gt; &lt;version&gt;</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Finally, if you&rsquo;re used to add something to your bash or zsh files to show the current language version in the command line, you&rsquo;re probably using something like <code>rvm-prompt</code>. In the case of ASDF you will need something a bit longer like this:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>asdf current ruby | awk -F&#39; &#39; &#39;{print $1}&#39;</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>This will get only the version (the <code>asdf current</code> command states which <code>.tool-versions</code> file it is using, so this is a longer result).</p>
<p>Other than that, you&rsquo;re all set. One version manager to rule them all. No more RVM, no more Virtualenv, no more NVM, etc. You can live happily ever after!</p>
]]></content:encoded><category>developer-tools</category><category>automation</category></item><item><title>Customizing Fedora 25 for Developers</title><link>https://akitaonrails.github.io/en/2017/01/06/customizing-fedora-25-for-developers/</link><guid isPermaLink="true">https://akitaonrails.github.io/en/2017/01/06/customizing-fedora-25-for-developers/</guid><pubDate>Fri, 06 Jan 2017 17:11:00 -0200</pubDate><description>&lt;p&gt;&lt;strong&gt;Update 01/18/2017:&lt;/strong&gt; Right after trying out Fedora for a few days, I decided to &lt;a href="http://www.akitaonrails.com/en/2017/01/10/arch-linux-a-melhor-distro-de-todas"target="_blank" rel="noopener"&gt;try Arch Linux&lt;/a&gt; and I couldn&amp;rsquo;t be happier. I recommend you try Arch too, it will probably surprise you. You may be also interested about &lt;a href="http://www.akitaonrails.com/en/2017/01/17/otimizando-o-linux-para-computadores-lentos"target="_blank" rel="noopener"&gt;advanced Linux tuning for better responsiveness&lt;/a&gt; on the desktop.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve been a long time Ubuntu user. Whenever I need to set up a Linux box I go straight to the latest LTS. Muscle memory, can&amp;rsquo;t avoid it.&lt;/p&gt;</description><content:encoded><![CDATA[<p><strong>Update 01/18/2017:</strong> Right after trying out Fedora for a few days, I decided to <a href="http://www.akitaonrails.com/en/2017/01/10/arch-linux-a-melhor-distro-de-todas"target="_blank" rel="noopener">try Arch Linux</a> and I couldn&rsquo;t be happier. I recommend you try Arch too, it will probably surprise you. You may be also interested about <a href="http://www.akitaonrails.com/en/2017/01/17/otimizando-o-linux-para-computadores-lentos"target="_blank" rel="noopener">advanced Linux tuning for better responsiveness</a> on the desktop.</p>
<p>I&rsquo;ve been a long time Ubuntu user. Whenever I need to set up a Linux box I go straight to the latest LTS. Muscle memory, can&rsquo;t avoid it.</p>
<p>But to replace my macOS, Unity is damn ugly, honest. I tried to customize Cinnamon and I almost liked it, and don&rsquo;t even get me started on KDE or XFCE.</p>
<p><a href="https://www.gnome.org/news/2016/09/gnome-3-22-released-the-future-is-now/"target="_blank" rel="noopener">GNOME 3.22</a>, on the other hand, is very handsome. I don&rsquo;t need to tweak it or hack it to make it look good. The default set of global shortcuts are spot on if you&rsquo;re a long term macOS user. I like almost everything about it.</p>
<p>I&rsquo;ve been curious about all the fuss surrounding the phase out of X.org into Wayland so I wanted to check it out.</p>
<p>The best distro I could find with those in mind is good old Fedora. RedHat (4) was the second Linux distro I tried after Slackware 1 back in the mid-90&rsquo;s. I come back and leave every couple of years. It&rsquo;s a good time to try it again.</p>
<p>The TL;DR is that I am quite delighted with <a href="https://getfedora.org/en/workstation/download/"target="_blank" rel="noopener">Fedora 25</a>. It does almost everything I need right out of the box.</p>
<p><img src="https://akitaonrails.s3.amazonaws.com/assets/image_asset/image/578/big_Screenshot_from_2017-01-06_16-58-17.png" alt="Fedora 25"  loading="lazy" /></p>
<p>I dusted off a 4-year-old Lenovo ThinkCentre Edge 71z Tower desktop and Lenovo IdeaPad G400s notebook. They are, respectively, a 2nd generation Core i5 SandyBridge 2.5Ghz and Core i3 2.4Ghz, with 8GB of RAM in the Tower and 4GB of RAM in the notebook. For a developer&rsquo;s routine, they are quite good enough. A better CPU wouldn&rsquo;t do a whole lot.</p>
<p>I was very happy to see that this old tower has an old Intel graphics card with a DVI port. Fortunately I had an old DVI-to-HDMI cable around and I was able to hook it up to my ultrawide LG monitor 21:9 (2560x180) and it properly scaled everything (macOS Sierra had a regression that required a hack to make it work!)</p>
<p>What hurts a lot are the super slow mechanical hard drives (7200rpm and 5400rpm). I just ordered a RAM upgrade and 2 Crucial MX300 compatible SSD drives. When those arrive, I will have the snappiness I need.</p>
<p>That being said, when you have a fresh Fedora 25 install, what to do next?</p>
<h3>for Ubuntu users<span class="hx:absolute hx:-mt-20" id="for-ubuntu-users"></span>
    <a href="#for-ubuntu-users" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Just remember this: instead of <code>apt-get</code> you get <code>dnf</code>. Fedora prior to version 22 used to have <code>yum</code>, but <code>dnf</code> supercedes it with basically the same command options.</p>
<p>You don&rsquo;t have the equivalent of <code>apt-get update</code> because it auto-updates. The rest is pretty much the same: <code>dnf install package</code> instead of <code>apt-get install package</code>, <code>dnf search package</code> instead of <code>apt-cache search package</code>, and so on. For a global upgrade, do <code>dnf upgrade</code> instead of <code>apt-get update &amp;&amp; apt-get upgrade</code>.</p>
<p>For services, instead of doing <code>sudo service restart memcached</code> you can do <code>sudo systemctl restart memcached</code>.</p>
<p>That&rsquo;s pretty much it for the most part. Read this <a href="https://fedoraproject.org/wiki/Differences_to_Ubuntu"target="_blank" rel="noopener">wiki page</a> for more command differences.</p>
<h3>Crystal Language support<span class="hx:absolute hx:-mt-20" id="crystal-language-support"></span>
    <a href="#crystal-language-support" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Let&rsquo;s say you want to learn this brand new language called &ldquo;Crystal&rdquo;: Ruby-like familiar syntax and standard libraries but Go-like native binary generation, with fast concurrency primitives and all the benefits of an LLVM optimized binary.</p>
<p>You should follow <a href="https://crystal-lang.org/docs/installation/on_redhat_and_centos.html"target="_blank" rel="noopener">their wiki</a> <a href="https://github.com/crystal-lang/crystal/wiki/All-required-libraries#fedora"target="_blank" rel="noopener">page</a> but this is what you need:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>sudo dnf -y install \
  gmp-devel \
  libbsd-devel \
  libedit-devel \
  libevent-devel \
  libxml2-devel \
  libyaml-devel \
  llvm-static \
  openssl-devel \
  readline-devel

sudo dnf -y install fedora-repos-rawhide
sudo dnf -y install gc gc-devel # get all dependencies from Fedora 25
sudo dnf -y install gc gc-devel --enablerepo=rawhide --best --allowerasing

sudo dnf -y install crystal</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>And that&rsquo;s it, a lot of dependencies but as it&rsquo;s pre-1.0 I believe they will improve this in the future.</p>
<h3>Ruby and Node.js support<span class="hx:absolute hx:-mt-20" id="ruby-and-nodejs-support"></span>
    <a href="#ruby-and-nodejs-support" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Rubyists have a number of Ruby version managers, but I personally like RVM. First, we need to install some <a href="http://www.socialquesting.com/blog/octopress-installation-fedora-25/"target="_blank" rel="noopener">other requirements</a> and go on with it:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>sudo dnf -y install patch autoconf gcc-c&#43;&#43; patch libffi-devel automake libtool bison sqlite-devel ImageMagick-devel nodejs git gitg
curl -sSL https://rvm.io/mpapis.asc | gpg2 --import
curl -L https://get.rvm.io | bash -s stable --ruby

sudo npm -g install brunch phantomjs</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>There you go, you should have the latest stable Ruby, Node, Npm and useful tools such as Brunch (required if you want to build Elixir-Phoenix web apps) and PhantomJS for automated acceptance tests in many languages.</p>
<p>Notice that we&rsquo;re installing Git, the optional <a href="https://git.gnome.org//browse/gitg"target="_blank" rel="noopener">GitG</a> which is a fantastic companion to your Git routine.</p>
<p><img src="https://akitaonrails.s3.amazonaws.com/assets/image_asset/image/583/big_Screenshot_from_2017-01-06_16-59-05.png" alt="GitG"  loading="lazy" /></p>
<h3>Postgresql, Redis, Memcached support<span class="hx:absolute hx:-mt-20" id="postgresql-redis-memcached-support"></span>
    <a href="#postgresql-redis-memcached-support" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>What&rsquo;s a web app without proper databases and cache services? Let&rsquo;s install them:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>sudo dnf -y install postgresql-server postgresql-contrib postgresql-devel memcached redis

sudo postgresql-setup --initdb
sudo sed -i.bak &#39;s/ident/trust/&#39; /var/lib/pgsql/data/pg_hba.conf # NEVER do this in production servers
sudo systemctl start postgresql

sudo su - postgres
createuser youruser -p
createdb youruser --owner=youruser</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Change <code>youruser</code> for the username of your current user account, of course.</p>
<h3>Java support<span class="hx:absolute hx:-mt-20" id="java-support"></span>
    <a href="#java-support" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>This is easy, let&rsquo;s install the latest <a href="http://www.2daygeek.com/install-java-openjdk-6-7-8-on-ubuntu-centos-debian-fedora-mint-rhel-opensuse-manjaro-archlinux/#"target="_blank" rel="noopener">OpenJDK 8</a> and web browser plugins.</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>sudo dnf -y install java-1.8.0-openjdk icedtea-web</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<h3>Go Support<span class="hx:absolute hx:-mt-20" id="go-support"></span>
    <a href="#go-support" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Even easier:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>sudo dnf -y install go</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Do not forget to edit your profile, such as <code>$HOME/.profile</code> and add the proper environment variables:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>export GOROOT=$HOME/go
export PATH=$PATH:$GOROOT/bin</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<h3>Elixir Support<span class="hx:absolute hx:-mt-20" id="elixir-support"></span>
    <a href="#elixir-support" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>There is an easy way, and a more complicated and time consuming one. Let&rsquo;s start with <a href="http://elixir-lang.org/install.html#unix-and-unix-like"target="_blank" rel="noopener">the easy one</a>:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>sudo dnf -y install erlang elixir
mix local.hex
mix local.rebar
mix archive.install https://github.com/phoenixframework/archives/raw/master/phoenix_new.ez</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>The problem is that packages for distros such as Fedora can take time to come out. For example, Elixir 1.4 has been out for a couple of days, but no upgrades for Fedora yet.</p>
<p>Another problem if you&rsquo;re professionally developing Elixir projects is that you will need an Elixir version manager, because you will end up getting client projects in different Elixir versions and you need to setup your environment accordingly. That&rsquo;s where <a href="https://github.com/asdf-vm/asdf"target="_blank" rel="noopener">asdf</a> comes in. You can follow <a href="https://gist.github.com/rubencaro/6a28138a40e629b06470"target="_blank" rel="noopener">this gist</a> but I will paste the important bits here:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>sudo dnf -y install make automake gcc gcc-c&#43;&#43; kernel-devel git wget openssl-devel ncurses-devel wxBase3 wxGTK3-devel m4

git clone https://github.com/asdf-vm/asdf.git ~/.asdf --branch v0.2.1

# For Ubuntu or other linux distros
echo &#39;. $HOME/.asdf/asdf.sh&#39; &gt;&gt; ~/.bashrc
echo &#39;. $HOME/.asdf/completions/asdf.bash&#39; &gt;&gt; ~/.bashrc

# restart your terminal or source the file above:
source ~/.bashrc

asdf plugin-add erlang https://github.com/asdf-vm/asdf-erlang.git
asdf plugin-add elixir https://github.com/asdf-vm/asdf-elixir.git

asdf install erlang 19.0
asdf install elixir 1.4.0

asdf global erlang 19.0
asdf global elixir 1.4.0</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Compiling Erlang from source will take a humongous amount of time, especially if you&rsquo;re using old CPUs like me. But this is how you both have access to the latest and greatest Elixir while also having the ability to choose older versions for client projects.</p>
<p>By the way, you can install additional asdf plugins to manage versions of other platforms such as Go, Rust, Node, Julia and many others. Check out <a href="https://github.com/asdf-vm/asdf"target="_blank" rel="noopener">their project page</a> for more details.</p>
<h3>Docker Support<span class="hx:absolute hx:-mt-20" id="docker-support"></span>
    <a href="#docker-support" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>You will probably want to have access to Docker as well, so <a href="https://docs.docker.com/engine/installation/linux/fedora/"target="_blank" rel="noopener">let&rsquo;s do this</a>:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>sudo dnf -y install docker docker-compose

# you can test if everything went ok with the infamous hello world
sudo docker run --rm hello-world</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<h2>Desktop Apps<span class="hx:absolute hx:-mt-20" id="desktop-apps"></span>
    <a href="#desktop-apps" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Once you have everything in place, let&rsquo;s configure the non-terminal aspects for a better experience.</p>
<h3>Terminator (and Terminix)<span class="hx:absolute hx:-mt-20" id="terminator-and-terminix"></span>
    <a href="#terminator-and-terminix" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p><img src="https://akitaonrails.s3.amazonaws.com/assets/image_asset/image/579/Screenshot_from_2017-01-06_16-59-53.png" alt="Terminator"  loading="lazy" /></p>
<p>Speaking of terminals, you will want to install <a href="https://gnometerminator.blogspot.com.br/p/introduction.html"target="_blank" rel="noopener">Terminator</a>. I really don&rsquo;t like using screen or tmux in my local machine (I can&rsquo;t get around those key bindings). I am more used to iTerm2 on macOS and Terminator is pretty much the same thing with similar key bindings. You definitely need to replace the default terminal for this one.</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>sudo dnf -y install terminator</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>You will also want to edit <code>~/.config/terminator/config</code> and add the following to make it better:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>[global_config]
  title_transmit_bg_color = &#34;#d30102&#34;
  focus = system
[keybindings]
[layouts]
  [[default]]
    [[[child1]]]
      parent = window0
      type = Terminal
      profile = default
    [[[window0]]]
      parent = &#34;&#34;
      type = Window
[plugins]
[profiles]
  [[default]]
    use_system_font = false
    font = Hack 12
    scrollback_lines = 2000
    palette = &#34;#073642:#dc322f:#859900:#b58900:#268bd2:#d33682:#2aa198:#eee8d5:#586e75:#cb4b16:#586e75:#657b83:#839496:#6c71c4:#93a1a1:#fdf6e3&#34;
    foreground_color = &#34;#eee8d5&#34;
    background_color = &#34;#002b36&#34;
    cursor_color = &#34;#eee8d5&#34;</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Another great option that was recommended to me is <a href="https://copr.fedorainfracloud.org/coprs/heikoada/terminix/"target="_blank" rel="noopener">Terminix</a>. This is how you install it:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>sudo dnf copr enable heikoada/terminix
sudo dnf -y install terminix</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<h3>Hack font<span class="hx:absolute hx:-mt-20" id="hack-font"></span>
    <a href="#hack-font" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>You will want to have a nicer font such as <a href="https://github.com/chrissimpkins/Hack"target="_blank" rel="noopener">Hack</a> around as well:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>dnf -y install dnf-plugins-core
dnf copr enable heliocastro/hack-fonts
dnf -y install hack-fonts</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<h3>Gnome Tweak Tool<span class="hx:absolute hx:-mt-20" id="gnome-tweak-tool"></span>
    <a href="#gnome-tweak-tool" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Now you will want to install <strong>Gnome Tweak Tool</strong> to be able to setup Hack as the default monospace font:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>sudo dnf -y install gnome-tweak-tool</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<h3>Vim, Zsh, Yadr<span class="hx:absolute hx:-mt-20" id="vim-zsh-yadr"></span>
    <a href="#vim-zsh-yadr" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p><img src="https://akitaonrails.s3.amazonaws.com/assets/image_asset/image/582/big_Screenshot_from_2017-01-06_16-59-36.png" alt="Vim gruvbox"  loading="lazy" /></p>
<p>I really like to use Vim so you can install it like this:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>sudo dnf -y install vim-enhanced vim-X11</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>And I really like to use <a href="https://github.com/Codeminer42/dotfiles"target="_blank" rel="noopener">YADR</a> to customize all aspects of my ZSH and Vim:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>sh -c &#34;`curl -fsSL https://raw.githubusercontent.com/skwp/dotfiles/master/install.sh `&#34;</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>I recommend you have Zsh, Vim, Ruby pre-installed before running the script above. Once you finish, I had to tweak the settings a bit:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>sed &#39;s/gtk2/gtk3&#39; ~/.vim/settings/yadr-appearance.vim</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>You&rsquo;d want to tweak that file as well, to add new fonts such as Hack, and right now I am more in the mood of &ldquo;gruvbox&rdquo; instead of &ldquo;solarized&rdquo; as Vim theme.</p>
<h3>GIMP Photoshop<span class="hx:absolute hx:-mt-20" id="gimp-photoshop"></span>
    <a href="#gimp-photoshop" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p><img src="https://akitaonrails.s3.amazonaws.com/assets/image_asset/image/580/big_Screenshot_from_2017-01-06_17-07-14.png" alt="Gimp with Photoshop Theme"  loading="lazy" /></p>
<p>If you&rsquo;re a web developer you will have to edit a couple of images sometimes. And if you&rsquo;re like me, Gimp is a freaking usability nightmare. But <a href="http://www.omgubuntu.co.uk/2016/08/make-gimp-look-like-photoshop-easy"target="_blank" rel="noopener">there are ways</a> to make it a bit <a href="https://github.com/doctormo/GimpPs"target="_blank" rel="noopener">more palatable</a>.</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>sudo dnf -y install gimp
sh -c &#34;$(curl -fsSL https://raw.githubusercontent.com/doctormo/GimpPs/master/tools/install.sh)&#34;</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>There you go, a Photoshop-like theme for Gimp to make it less ugly.</p>
<h3>Spotify<span class="hx:absolute hx:-mt-20" id="spotify"></span>
    <a href="#spotify" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>What would we, developers, be without music to concentrate?</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>dnf config-manager --add-repo=http://negativo17.org/repos/fedora-spotify.repo
dnf -y install spotify-client</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<h3>CoreBird<span class="hx:absolute hx:-mt-20" id="corebird"></span>
    <a href="#corebird" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p><img src="https://akitaonrails.s3.amazonaws.com/assets/image_asset/image/581/big_Screenshot_from_2017-01-06_17-08-43.png" alt="CoreBird"  loading="lazy" /></p>
<p>I am so glad that someone built a very competent and elegant Twitter client for Linux. Install CoreBird:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>dnf -y install corebird</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>It&rsquo;s probably even better than the official Mac version.</p>
<h3>Tweaking the title bar<span class="hx:absolute hx:-mt-20" id="tweaking-the-title-bar"></span>
    <a href="#tweaking-the-title-bar" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>I found <a href="http://blog.samalik.com/make-your-gnome-title-bars-smaller/"target="_blank" rel="noopener">this hack</a> to try to make the Gnome title bars a bit less fat, which is about the only complaint I have for the look-and-feel so far:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>tee ~/.config/gtk-3.0/gtk.css &lt;&lt;-EOF
.header-bar.default-decoration {
 padding-top: 3px;
 padding-bottom: 3px;
 font-size: 0.8em;
}

.header-bar.default-decoration .button.titlebutton {
 padding: 0px;
}
EOF</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<h3>Conclusion<span class="hx:absolute hx:-mt-20" id="conclusion"></span>
    <a href="#conclusion" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Most of everything you need is web based, so Gmail, Slack, all work just fine. Fire up Chromium, Firefox or install <a href="http://meetfranz.com/"target="_blank" rel="noopener">Franz</a> or <a href="http://thomas101.github.io/wmail/"target="_blank" rel="noopener">WMail</a> if you have to. Unfortunately everything that is web based consumes a lot of RAM, and this is really bad. I do miss good old, slim, native apps. Web-based apps are a huge hassle.</p>
<p>They &ldquo;work&rdquo;, but I&rsquo;d rather have a good native app. On the other hand, Dropbox and Skype have really terrible client apps. They are very poorly maintained, full of bugs, and terrible support. I&rsquo;d rather not have them.</p>
<p>I was trying to get used to Thunderbird while on Ubuntu. Geary is still not good enough. But I was surprised when I tried Evolution again. It has the only thing I really want from any email client: a damn shortcut to move emails to folders: Ctrl-Shift-V (!!) How hard can that be??</p>
<p>Gnome 3 has a global Online Accounts repository in the Settings where you can register social networks such as Facebook and Google, but the Google support is <a href="https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=820913"target="_blank" rel="noopener">buggy</a>. It expires every time, so don&rsquo;t use Evolution with it. Add the Imap/Smtp information manually instead. Email and Calendar data is properly synced that way.</p>
<p>You should have all your passwords in a LastPass account by now. Authy is a Chrome extension, so your multi-factor authentication should also just work.</p>
<p>My personal bank and investment companies, with their ugly Java applets, work just fine with Chromium and IcedTea, so I&rsquo;m ok there too.</p>
<p>I just have to figure out the easiest backup strategy to have everything really secure. On the installation process, do not forget to choose the encrypted partition option - and if you do, definitely back up your data regularly as I&rsquo;ve heard of bugs during upgrades that made the encrypted partitions inaccessible. Be secure and also be careful.</p>
<p>As usual, from my macOS the only 2 things I will really miss are Apple Keynote (it&rsquo;s really amazing as no one was able to make a slick and fast presentation tool as good as Keynote) and iMovie for quick video editing (although <a href="https://kdenlive.org/"target="_blank" rel="noopener">Kdenlive</a> is a very good alternative).</p>
<p>You even have built-in <a href="https://wiki.gnome.org/Gnome3CheatSheet"target="_blank" rel="noopener">shortcuts</a> to screen capture a window or an area and <a href="https://fedoramagazine.org/taking-screencast-fedora/"target="_blank" rel="noopener">record a screencast</a>!</p>
<p>Compared to my Ubuntu configuration, this Fedora 25 is really a pleasure to use. A competent macOS replacement. I highly recommend it!</p>
<p>And as I said at the update in the beginning of the post. Do check out <a href="http://www.akitaonrails.com/en/2017/01/10/arch-linux-a-melhor-distro-de-todas"target="_blank" rel="noopener">Arch Linux</a> and how to <a href="http://www.akitaonrails.com/en/2017/01/17/otimizando-o-linux-para-computadores-lentos"target="_blank" rel="noopener">optimize your distro to be more responsive</a>, particularly on old hardware.</p>
]]></content:encoded><category>linux</category><category>developer-tools</category></item><item><title>Ubuntu 16.04 LTS Xenial on Vagrant on Vmware Fusion</title><link>https://akitaonrails.github.io/en/2016/09/21/ubuntu-16-04-lts-xenial-on-vagrant-on-vmware-fusion/</link><guid isPermaLink="true">https://akitaonrails.github.io/en/2016/09/21/ubuntu-16-04-lts-xenial-on-vagrant-on-vmware-fusion/</guid><pubDate>Wed, 21 Sep 2016 18:08:00 -0300</pubDate><description>&lt;p&gt;I&amp;rsquo;m old school. I know the cool kids are all playing around with Docker nowadays, but I like to have a full-blown linux environment with all dependencies in one place. I will leave volatile boxes for the cloud.&lt;/p&gt;
&lt;p&gt;I like to keep a Vagrant box around, because no matter how messy an OS upgrade can go (looking at ya macOS), I know my development box will just work.&lt;/p&gt;
&lt;p&gt;But even with everything virtualized and isolated, things can still go wrong. I am currently using &lt;a href="https://www.vagrantup.com/downloads.html"target="_blank" rel="noopener"&gt;Vagrant 1.8.5&lt;/a&gt;, with the &lt;a href="https://www.vagrantup.com/vmware/"target="_blank" rel="noopener"&gt;vagrant-vmware-fusion plugin 4.0.11&lt;/a&gt; and Vmware Fusion 8.5 on El Capitan (even though macOS Sierra just launched, I will wait at least 1 month before upgrading, there is nothing there that is worth the risk).&lt;/p&gt;</description><content:encoded><![CDATA[<p>I&rsquo;m old school. I know the cool kids are all playing around with Docker nowadays, but I like to have a full-blown linux environment with all dependencies in one place. I will leave volatile boxes for the cloud.</p>
<p>I like to keep a Vagrant box around, because no matter how messy an OS upgrade can go (looking at ya macOS), I know my development box will just work.</p>
<p>But even with everything virtualized and isolated, things can still go wrong. I am currently using <a href="https://www.vagrantup.com/downloads.html"target="_blank" rel="noopener">Vagrant 1.8.5</a>, with the <a href="https://www.vagrantup.com/vmware/"target="_blank" rel="noopener">vagrant-vmware-fusion plugin 4.0.11</a> and Vmware Fusion 8.5 on El Capitan (even though macOS Sierra just launched, I will wait at least 1 month before upgrading, there is nothing there that is worth the risk).</p>
<p>If you&rsquo;re installing a brand new box for the first time, this is the bare-bones <code>Vagrantfile</code> configuration I am using:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ruby" data-lang="ruby"><span class="line"><span class="cl"><span class="c1"># -*- mode: ruby -*-</span>
</span></span><span class="line"><span class="cl"><span class="c1"># vi: set ft=ruby :</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="no">Vagrant</span><span class="o">.</span><span class="n">configure</span><span class="p">(</span><span class="mi">2</span><span class="p">)</span> <span class="k">do</span> <span class="o">|</span><span class="n">config</span><span class="o">|</span>
</span></span><span class="line"><span class="cl">  <span class="n">config</span><span class="o">.</span><span class="n">vm</span><span class="o">.</span><span class="n">box</span> <span class="o">=</span> <span class="s2">&#34;bento/ubuntu-16.04&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="n">config</span><span class="o">.</span><span class="n">vm</span><span class="o">.</span><span class="n">network</span> <span class="ss">:forwarded_port</span><span class="p">,</span> <span class="ss">guest</span><span class="p">:</span> <span class="mi">8080</span><span class="p">,</span> <span class="ss">host</span><span class="p">:</span> <span class="mi">8080</span>
</span></span><span class="line"><span class="cl">  <span class="n">config</span><span class="o">.</span><span class="n">vm</span><span class="o">.</span><span class="n">network</span> <span class="ss">:forwarded_port</span><span class="p">,</span> <span class="ss">guest</span><span class="p">:</span> <span class="mi">3000</span><span class="p">,</span> <span class="ss">host</span><span class="p">:</span> <span class="mi">3000</span>
</span></span><span class="line"><span class="cl">  <span class="n">config</span><span class="o">.</span><span class="n">vm</span><span class="o">.</span><span class="n">network</span> <span class="ss">:forwarded_port</span><span class="p">,</span> <span class="ss">guest</span><span class="p">:</span> <span class="mi">3001</span><span class="p">,</span> <span class="ss">host</span><span class="p">:</span> <span class="mi">3001</span>
</span></span><span class="line"><span class="cl">  <span class="n">config</span><span class="o">.</span><span class="n">vm</span><span class="o">.</span><span class="n">network</span> <span class="ss">:forwarded_port</span><span class="p">,</span> <span class="ss">guest</span><span class="p">:</span> <span class="mi">4000</span><span class="p">,</span> <span class="ss">host</span><span class="p">:</span> <span class="mi">4000</span>
</span></span><span class="line"><span class="cl">  <span class="n">config</span><span class="o">.</span><span class="n">vm</span><span class="o">.</span><span class="n">network</span> <span class="ss">:forwarded_port</span><span class="p">,</span> <span class="ss">guest</span><span class="p">:</span> <span class="mi">5555</span><span class="p">,</span> <span class="ss">host</span><span class="p">:</span> <span class="mi">5555</span>
</span></span><span class="line"><span class="cl">  <span class="n">config</span><span class="o">.</span><span class="n">vm</span><span class="o">.</span><span class="n">network</span> <span class="ss">:forwarded_port</span><span class="p">,</span> <span class="ss">guest</span><span class="p">:</span> <span class="mi">5556</span><span class="p">,</span> <span class="ss">host</span><span class="p">:</span> <span class="mi">5556</span>
</span></span><span class="line"><span class="cl">  <span class="n">config</span><span class="o">.</span><span class="n">vm</span><span class="o">.</span><span class="n">network</span> <span class="ss">:forwarded_port</span><span class="p">,</span> <span class="ss">guest</span><span class="p">:</span> <span class="mi">3808</span><span class="p">,</span> <span class="ss">host</span><span class="p">:</span> <span class="mi">3808</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="n">config</span><span class="o">.</span><span class="n">vm</span><span class="o">.</span><span class="n">network</span> <span class="s2">&#34;private_network&#34;</span><span class="p">,</span> <span class="ss">ip</span><span class="p">:</span> <span class="s2">&#34;192.168.0.100&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="n">config</span><span class="o">.</span><span class="n">vm</span><span class="o">.</span><span class="n">synced_folder</span> <span class="s2">&#34;/Users/akitaonrails/Sites&#34;</span><span class="p">,</span> <span class="s2">&#34;/vagrant&#34;</span><span class="p">,</span> <span class="ss">nfs</span><span class="p">:</span> <span class="kp">true</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="n">config</span><span class="o">.</span><span class="n">vm</span><span class="o">.</span><span class="n">provider</span> <span class="ss">:vmware_fusion</span> <span class="k">do</span> <span class="o">|</span><span class="n">v</span><span class="o">|</span>
</span></span><span class="line"><span class="cl">    <span class="n">v</span><span class="o">.</span><span class="n">vmx</span><span class="o">[</span><span class="s2">&#34;memsize&#34;</span><span class="o">]</span> <span class="o">=</span> <span class="s2">&#34;2048&#34;</span>
</span></span><span class="line"><span class="cl">  <span class="k">end</span>
</span></span><span class="line"><span class="cl"><span class="k">end</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>I usually go in the Vmware settings for the virtual machine and enable an extra processor (as my Macbook has 8 virtual cores to share) and enable hypervisor (support for Intel&rsquo;s VT-x/EPT).</p>
<p>As a rule of thumb, the very first thing I always do is set the locale to en_US.UTF-8:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>sudo locale-gen &#34;en_US.UTF-8&#34;
sudo dpkg-reconfigure locales
sudo update-locale LC_ALL=en_US.UTF-8 LANG=en_US.UTF-8</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>And just to make sure, add the following to <code>/etc/environment</code>:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>LC_ALL=en_US.UTF-8
LANG=en_US.UTF-8</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>You must set UTF-8 before you install packages such as Postgresql.</p>
<p>Then I upgrade packages and install the basics:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>sudo apt-get update &amp;&amp; sudo apt-get upgrade
sudo apt-get install open-vm-tools build-essential libssl-dev exuberant-ctags ncurses-term ack-grep silversearcher-ag fontconfig imagemagick libmagickwand-dev python-software-properties redis-server libhiredis-dev memcached libmemcached-dev</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>This will install important tools such as Imagemagick, Memcached and Redis for us.</p>
<p>Now, to <a href="https://www.digitalocean.com/community/tutorials/how-to-install-and-use-postgresql-on-ubuntu-16-04"target="_blank" rel="noopener">install Postgresql</a>:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>sudo apt-get install postgresql-9.5 postgresql-contrib postgresql-server-dev-9.5</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Create the superuser for vagrant:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>sudo -i -u postgres
createuser --interactive

Enter name of role to add: vagrant
Shall the new role be a superuser? (y/n) y</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>And <strong>only for the development environment</strong> edit <code>/etc/postgresql/9.5/main/pg_hba.conf</code> and change the following:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code># &#34;local&#34; is for Unix domain socket connections only
local   all             all                                     trust
# IPv4 local connections:
host    all             all             127.0.0.1/32            trust
# IPv6 local connections:
host    all             all             ::1/128                 trust</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>This makes your life easier while programming. If you did everything right until now, you will have your PG with proper unicode encoding and without bothering with passwords when you do <code>bin/rails db:create</code>. If you didn&rsquo;t configure your locale properly before, you can follow <a href="https://gist.github.com/turboladen/6790847"target="_blank" rel="noopener">this gist</a> to manually set PG&rsquo;s locale to UTF-8.</p>
<p>Installing <a href="https://rvm.io/rvm/install"target="_blank" rel="noopener">Ruby</a> is still better done through RVM:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>gpg --keyserver hkp://keys.gnupg.net --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3
\curl -sSL https://get.rvm.io | bash
source $HOME/.rvm/scripts/rvm
rvm install 2.3.1
rvm use 2.3.1 --default</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>And I prefer using <a href="https://github.com/skwp/dotfiles"target="_blank" rel="noopener">YADR</a> as my default dotfiles, replacing Bash with ZSH. Compared to other dotfiles, I like this one because I usually don&rsquo;t have to tweak it at all. I won&rsquo;t even configure anything about RVM after installing because YADR takes care of that already.</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>sh -c &#34;`curl -fsSL https://raw.githubusercontent.com/skwp/dotfiles/master/install.sh `&#34;</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>To update it (or resume in case it breaks for some reason):</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>cd .yadr
rake update</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>The only 2 tweaks I have to do are changing my <a href="https://github.com/altercation/solarized/tree/master/iterm2-colors-solarized"target="_blank" rel="noopener">iTerm2</a> profile to use <a href="http://ethanschoonover.com/solarized"target="_blank" rel="noopener">Solarized</a>, and adding the following 2 lines to the top of the <code>.vimrc</code> file:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>scriptencoding utf-8
set encoding=utf-8</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Next step, <a href="https://www.digitalocean.com/community/tutorials/how-to-install-node-js-on-ubuntu-16-04"target="_blank" rel="noopener">install NodeJS</a>:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>curl -sL https://deb.nodesource.com/setup_6.x | sudo -E bash -
sudo apt-get install nodejs</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Next step, <a href="https://www.digitalocean.com/community/tutorials/how-to-install-java-with-apt-get-on-ubuntu-16-04"target="_blank" rel="noopener">install Java</a>. You can choose Oracle&rsquo;s installer, but I believe the openjdk should be enough:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>sudo apt-get install default-jdk</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>We will need Java for <a href="https://www.digitalocean.com/community/tutorials/how-to-install-and-configure-elasticsearch-on-ubuntu-16-04"target="_blank" rel="noopener">Elasticsearch</a> 2.4.0:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>wget https://download.elastic.co/elasticsearch/release/org/elasticsearch/distribution/deb/elasticsearch/2.4.0/elasticsearch-2.4.0.deb &amp;&amp; sudo dpkg -i elasticsearch-2.4.0.deb</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Now you can start it manually with <code>sudo /etc/init.d/elasticsearch start</code>, and you want to leave it that way because it consumes a lot of RAM, so you should only start it when you really need it.</p>
<p>With Java in place, we can also install <a href="http://leiningen.org/"target="_blank" rel="noopener">Leiningen</a> to have Clojure ready.</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>echo &#34;PATH=$PATH:~/bin&#34; &gt;&gt; ~/.zsh.after/bin.zsh
mkdir ~/bin &amp;&amp; cd ~/bin
wget https://raw.githubusercontent.com/technomancy/leiningen/stable/bin/lein
chmod a&#43;x lein
lein</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Leiningen will install its dependencies and you can follow its <a href="https://github.com/technomancy/leiningen/blob/stable/doc/TUTORIAL.md"target="_blank" rel="noopener">tutorial</a> to get started.</p>
<p>Installing <a href="https://www.rust-lang.org/en-US/downloads.html"target="_blank" rel="noopener">Rust</a> is as easy:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>curl -sSf https://static.rust-lang.org/rustup.sh | sh</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Installing <a href="https://crystal-lang.org/docs/installation/on_debian_and_ubuntu.html"target="_blank" rel="noopener">Crystal</a>, also easy:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>curl https://dist.crystal-lang.org/apt/setup.sh | sudo bash
sudo apt-get install crystal</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Installing <a href="https://www.digitalocean.com/community/tutorials/how-to-install-go-1-6-on-ubuntu-16-04"target="_blank" rel="noopener">Go</a> is not difficult, but more manual:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>wget https://storage.googleapis.com/golang/go1.7.1.linux-amd64.tar.gz
tar xvfz go1.7.1.linux-amd64.tar.gz
chown -R root:root .go
sudo mv go /usr/local
touch ~/.zsh.after/go.zsh
echo &#34;export GOPATH=$HOME/go&#34; &gt;&gt; ~/.zsh.after/go.zsh
echo &#34;export PATH=$PATH:/usr/local/go/bin:$GOPATH/bin&#34; &gt;&gt; ~/.zsh.after/go.zsh</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Once you install go and set its work path, we can install some useful tools such as <a href="https://github.com/ddollar/forego"target="_blank" rel="noopener">forego</a> and <a href="https://github.com/alco/goon#goon"target="_blank" rel="noopener">goon</a> (that Elixir&rsquo;s Hex can optionally use):</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>go get -u github.com/ddollar/forego
go get -u github.com/alco/goon</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>And speaking of <a href="http://elixir-lang.org/install.html"target="_blank" rel="noopener">Elixir</a>, we saved the best for last:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>wget https://packages.erlang-solutions.com/erlang-solutions_1.0_all.deb &amp;&amp; sudo dpkg -i erlang-solutions_1.0_all.deb
sudo apt-get update
sudo apt-get install esl-erlang elixir</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>And this is it, a very straightforward tutorial to have a modern development environment ready to go. These are the basic software development tools that I believe should be in everybody&rsquo;s toolbelt for the following years.</p>
<p>Honestly, I am not so much into Clojure and Go as I think I should be. And I didn&rsquo;t give .NET Core a lot of time yet, but I will explore those in more detail in the future.</p>
]]></content:encoded><category>linux</category><category>developer-tools</category></item><item><title>The Year of Linux on the Desktop - It's Usable!</title><link>https://akitaonrails.github.io/en/2016/07/26/the-year-of-linux-on-the-desktop-it-s-usable/</link><guid isPermaLink="true">https://akitaonrails.github.io/en/2016/07/26/the-year-of-linux-on-the-desktop-it-s-usable/</guid><pubDate>Tue, 26 Jul 2016 14:13:00 -0300</pubDate><description>&lt;p&gt;07/23/16: coincidentally I posted this review a day before the final release :-) So the final build is 14393 and &lt;a href="http://arstechnica.com/information-technology/2016/07/windows-10-anniversary-update-is-ready-to-go-and-free-for-just-a-few-more-days/"target="_blank" rel="noopener"&gt;it&amp;rsquo;s available&lt;/a&gt; for free right now!&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s been 3 months since I posted &lt;a href="https://akitaonrails.github.io/en/2016/04/12/the-year-of-linux-on-the-desktop-by-microsoft"&gt;my initial impressions&lt;/a&gt; on Windows 10 Anniversary Edition&amp;rsquo;s most important feature: Bash on Windows. My conclusion at the time was that it was not ready for prime time yet.&lt;/p&gt;
&lt;p&gt;My conclusion as of right now, on July 26th is that it&amp;rsquo;s finally usable enough for web developers, particularly for Ruby developers who always suffered through lack of Windows support.&lt;/p&gt;</description><content:encoded><![CDATA[<p>07/23/16: coincidentally I posted this review a day before the final release :-) So the final build is 14393 and <a href="http://arstechnica.com/information-technology/2016/07/windows-10-anniversary-update-is-ready-to-go-and-free-for-just-a-few-more-days/"target="_blank" rel="noopener">it&rsquo;s available</a> for free right now!</p>
<p>It&rsquo;s been 3 months since I posted <a href="/en/2016/04/12/the-year-of-linux-on-the-desktop-by-microsoft">my initial impressions</a> on Windows 10 Anniversary Edition&rsquo;s most important feature: Bash on Windows. My conclusion at the time was that it was not ready for prime time yet.</p>
<p>My conclusion as of right now, on July 26th is that it&rsquo;s finally usable enough for web developers, particularly for Ruby developers who always suffered through lack of Windows support.</p>
<p><img src="https://akitaonrails.s3.amazonaws.com/assets/image_asset/image/543/big_Screen_Shot_2016-07-26_at_13.28.48.png" alt="It’s alive!"  loading="lazy" /></p>
<p>Installation process is the same. You must be signed up to the <a href="http://www.howtogeek.com/249966/how-to-install-and-use-the-linux-bash-shell-on-windows-10/"target="_blank" rel="noopener">Windows Insider</a> program, wait at least one day if this is your first time. Enable the <strong>Fast ring</strong> of updates, install the Preview edition from normal Windows Update and then turn on the &ldquo;Windows Subsystem for Linux (Beta)&rdquo; feature.</p>
<blockquote>
  <p>Last time I was testing Windows 10 over Virtualbox over Ubuntu 14.04 on a Dell Inspiron notebook (8 cores i7 with 16GB of RAM). It was super slow, I don&rsquo;t recommend it at all. Now I am back on my trustworthy Macbook Pro 2013 with 16GB of RAM and SSD running VMWare Fusion, and Windows 10 flies here. Super recommended.</p>

</blockquote>
<p>Once you do all that, you can start the &ldquo;Bash on Ubuntu on Windows&rdquo; (a mouthful). The first good surprise is that it prompts you to register a new username instead of just falling back to Root. As I said in my previous post, it&rsquo;s good practice to create a new user and add it to the sudoers group, and this is what it does. So you can install packages using &ldquo;sudo apt-get install&rdquo;.</p>
<p>You should follow my <a href="/en/2016/04/12/the-year-of-linux-on-the-desktop-by-microsoft">previous post</a> for all the packages and configurations I normally do in a development Linux box.</p>
<p>RVM now works! I was able to install Ruby 2.3.1 through RVM without any problems whatsoever.</p>
<p>I was able to <code>git clone</code> a small Rails project and properly <code>bundle install</code>. All gems were downloaded, native extensions compiled without any flaws.</p>
<p>Some things still don&rsquo;t work. For example, you won&rsquo;t be able to finish the Postgresql 9.3 installation. It will download and install but the cluster setup fails as you can follow through <a href="https://github.com/microsoft/WSL/issues/61"target="_blank" rel="noopener">this issue</a> thread.</p>
<p>But you don&rsquo;t need to have <strong>everything</strong> installed under Ubuntu, you can just fall back to the native <a href="https://www.postgresql.org/download/windows/"target="_blank" rel="noopener">Postgresql for Windows</a> and edit your <code>config/database.yml</code> to point to server <code>127.0.0.1</code> and port <code>5432</code>. On the Ubuntu side you just need to install <code>libpq-dev</code> so the <code>pg</code> gem can compile its native extensions and that&rsquo;s it.</p>
<p>Smaller services such as Memcached or Redis install properly with <code>apt-get</code> but they won&rsquo;t auto-start through Upstart. But you can start them up manually and use something like <a href="https://github.com/ddollar/foreman"target="_blank" rel="noopener">Foreman</a> to control the processes. They both start and work well enough, so you can test caching in your Rails projects and also test Sidekiq workers.</p>
<p>I know this is still a Preview, so more bug fixes and possibly new features are still coming before the final release in August. What bugs me the most is that every command I run with <code>sudo</code> takes a few seconds to start. It&rsquo;s annoying, but it works in the end.</p>
<p>Node.js 6.3.1 successfully installs and runs. I was able to <code>npm i</code> and <code>node server.js</code> on Openshift&rsquo;s Node <a href="https://github.com/openshift/nodejs-ex"target="_blank" rel="noopener">example repository</a>.</p>
<p>Crystal 0.18.7 installs successfully and properly compiled my <a href="https://github.com/akitaonrails/cr_manga_downloadr"target="_blank" rel="noopener">Manga Downloader</a> project. It ran my built-in performance test in 15 minutes. The performance is modest, but it runs correctly to the end. (And yes, Crystal runs on Windows now too!).</p>
<p>Go 1.6 works. I just did a <code>go get</code> to install Martini and just ran the simple &ldquo;Hello World&rdquo; server. Compiles, starts and executes very fast as expected.</p>
<p>Unfortunately, Elixir 1.3.1 crashes, I don&rsquo;t know why yet.</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>$ iex
Crash dump is being written to: erl_crash.dump...done
erl_child_setup closed</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Actually, Erlang itself crashes by just trying to run <code>erl</code>. None of the Elixir tools work as a result. No iex, no mix. The funny thing is that it was working in the initial Preview. So either it&rsquo;s something in the new Preview or something in the newest Erlang releases. There are <a href="https://github.com/microsoft/WSL/issues?utf8=%e2%9c%93&amp;q=is%3Aissue%20elixir"target="_blank" rel="noopener">open issues</a> regarding this problem, so let&rsquo;s hope it gets fixed soon.</p>
<p><a name="best-windows-dev-env"></a></p>
<h3>&ldquo;The Best Environment for Rails on Windows&rdquo;<span class="hx:absolute hx:-mt-20" id="the-best-environment-for-rails-on-windows"></span>
    <a href="#the-best-environment-for-rails-on-windows" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>I have <a href="https://web.archive.org/web/20160814041945/http://www.akitaonrails.com/2009/1/13/the-best-environment-for-rails-on-windows"target="_blank" rel="noopener">this very old 2009 post</a> to guide developers that are locked on Windows to implement Rails projects. The first advice is to avoid Ruby for Windows. I really commend the efforts of great developers such as Luis Lavena, who invested a lot of time to make it work well enough. But unfortunately the reality is that Ruby is made for Linux environments, it binds to native extensions in C that have lots of dependencies that are not easy to make available on Windows.</p>
<p>So the best option up until now was to install Vagrant (through Virtualbox or, even better, VMWare) as the runtime and use Windows-available editors such as Sublime Text 3 or Atom.</p>
<p>Now you can avoid the Vagrant/virtualization part and directly use &ldquo;Bash on Ubuntu on Windows&rdquo;. It&rsquo;s so complete that I can even use ZSH and install complex dotfiles such as YADR. You can run Postgresql for Windows and connect to localhost:5432 in your Rails application or any web application that requires Postgresql for example.</p>
<p>You can install ConEmu as a better terminal emulator than the stupidly bad cmd.exe default console. Follow <a href="https://conemu.github.io/en/BashOnWindows.html"target="_blank" rel="noopener">this article</a> to get news on its support of Bash on Windows. Right now you have to edit the &ldquo;Ctrl-V&rdquo; hotkey to something else (&ldquo;Ctrl-Shift-V&rdquo;), arrow keys don&rsquo;t work well on Vim, and you can add a Default Task for Bash like this: <code>%windir%\system32\bash.exe ~ -cur_console:p</code></p>
<p><img src="https://akitaonrails.s3.amazonaws.com/assets/image_asset/image/544/big_Screen_Shot_2016-07-28_at_14.13.36.png" alt="Developing Rails on Windows"  loading="lazy" /></p>
<h3>Conclusion<span class="hx:absolute hx:-mt-20" id="conclusion"></span>
    <a href="#conclusion" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>So, yes, at least from this version I tested (installed on July 25th) this is a <strong>usable</strong> &ldquo;Bash on Ubuntu on Windows&rdquo; and web developers from Ruby to Javascript to Crystal to Go can really start testing and trying to make Windows 10 Anniversary their primary platform for serious Linux-based development.</p>
<p>Add Sublime Text or Atom (or Visual Studio, if that&rsquo;s your thing) and you should be good to go. I expect the next releases to fix some of the bugs and performance issues, but compared to what we saw in April, it&rsquo;s a huge improvement.</p>
<p>Kudos to Microsoft for that!</p>
<p>And if you want to know more hardcore details on how the Windows Subsystem for Linux is actually implemented, I recommend this series of blog posts from MSDN itself:</p>
<ul>
<li><a href="https://blogs.msdn.microsoft.com/wsl/2016/04/22/windows-subsystem-for-linux-overview/"target="_blank" rel="noopener">Windows Subsystem for Linux Overview</a></li>
<li><a href="https://blogs.msdn.microsoft.com/wsl/2016/05/23/pico-process-overview/"target="_blank" rel="noopener">Pico Process Overview</a></li>
<li><a href="https://blogs.msdn.microsoft.com/wsl/2016/06/08/wsl-system-calls/"target="_blank" rel="noopener">WSL System Calls</a></li>
<li><a href="https://blogs.msdn.microsoft.com/wsl/2016/06/15/wsl-file-system-support/"target="_blank" rel="noopener">WSL File System Support</a></li>
</ul>
]]></content:encoded><category>microsoft</category><category>linux</category><category>developer-tools</category><category>off-topic</category></item><item><title>The Year of Linux on the Desktop, by Microsoft??</title><link>https://akitaonrails.github.io/en/2016/04/12/the-year-of-linux-on-the-desktop-by-microsoft/</link><guid isPermaLink="true">https://akitaonrails.github.io/en/2016/04/12/the-year-of-linux-on-the-desktop-by-microsoft/</guid><pubDate>Tue, 12 Apr 2016 18:33:00 -0300</pubDate><description>&lt;p&gt;So, it&amp;rsquo;s finally here. I wrote about the announcement at the Build event a few days ago &lt;a href="https://akitaonrails.github.io/en/2016/03/31/war-is-over-or-is-it-a-new-dawn-for-microsoft"&gt;here&lt;/a&gt;. Now Microsoft is teasing us a bit more and &lt;a href="http://thehackernews.com/2016/04/how-to-run-ubuntu-on-windows-10.html"target="_blank" rel="noopener"&gt;released the first Insider Build Preview&lt;/a&gt;. The label is &amp;ldquo;Build 14316.rs1_release.160402-2217&amp;rdquo;; make sure that&amp;rsquo;s exactly the one you have before going further.&lt;/p&gt;
&lt;p&gt;To get it, you must have the following requirements:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Have an activated Windows 10 64-bits&lt;/li&gt;
&lt;li&gt;Sign up for the &lt;a href="https://insider.windows.com/"target="_blank" rel="noopener"&gt;Windows Insider&lt;/a&gt; Program. If it&amp;rsquo;s your first time it can take up to 24 hours to activate&lt;/li&gt;
&lt;li&gt;In your Windows Update Settings, Advanced Options, you must choose to &amp;ldquo;Get Started&amp;rdquo; in the Insider option and also choose the &amp;ldquo;Fast&amp;rdquo; Ring option. Now, when you Check for Updates, the Preview 14316 should show up. If not, wait until your account is refreshed by Microsoft.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a href="https://akitaonrails.s3.amazonaws.com/assets/image_asset/image/538/windows_update_settings.jpg"target="_blank" rel="noopener"&gt;&lt;img src="https://akitaonrails.s3.amazonaws.com/assets/image_asset/image/538/big_windows_update_settings.jpg" alt="windows update settings" loading="lazy" /&gt;&lt;/a&gt;&lt;/p&gt;</description><content:encoded><![CDATA[<p>So, it&rsquo;s finally here. I wrote about the announcement at the Build event a few days ago <a href="/en/2016/03/31/war-is-over-or-is-it-a-new-dawn-for-microsoft">here</a>. Now Microsoft is teasing us a bit more and <a href="http://thehackernews.com/2016/04/how-to-run-ubuntu-on-windows-10.html"target="_blank" rel="noopener">released the first Insider Build Preview</a>. The label is &ldquo;Build 14316.rs1_release.160402-2217&rdquo;; make sure that&rsquo;s exactly the one you have before going further.</p>
<p>To get it, you must have the following requirements:</p>
<ul>
<li>Have an activated Windows 10 64-bits</li>
<li>Sign up for the <a href="https://insider.windows.com/"target="_blank" rel="noopener">Windows Insider</a> Program. If it&rsquo;s your first time it can take up to 24 hours to activate</li>
<li>In your Windows Update Settings, Advanced Options, you must choose to &ldquo;Get Started&rdquo; in the Insider option and also choose the &ldquo;Fast&rdquo; Ring option. Now, when you Check for Updates, the Preview 14316 should show up. If not, wait until your account is refreshed by Microsoft.</li>
</ul>
<p><a href="https://akitaonrails.s3.amazonaws.com/assets/image_asset/image/538/windows_update_settings.jpg"target="_blank" rel="noopener"><img src="https://akitaonrails.s3.amazonaws.com/assets/image_asset/image/538/big_windows_update_settings.jpg" alt="windows update settings"  loading="lazy" /></a></p>
<p>You must have, at the very least, 10GB of available space in your main partition, so keep that in mind. Another caveat: if you&rsquo;re like me and you&rsquo;re testing under Virtualbox, also bear in mind that to resize a virtual drive you must delete your snapshots, and the merging process can take a ridiculously long time.</p>
<p>Once it&rsquo;s installed, you must go to the Developer options in the &ldquo;Update &amp; Security&rdquo; Control Panel and change your profile to &ldquo;Developer Mode&rdquo;. This &ldquo;Bash on Windows&rdquo; feature will show up under the Windows Features list. It&rsquo;s intended for <strong>developers only</strong>, not to be used in production servers.</p>
<p>Once you have the Preview installed you must be able to fire up the old cmd.exe console (or any other better console such as <a href="https://conemu.github.io/"target="_blank" rel="noopener">ConEmu</a>) and type in &ldquo;bash&rdquo;; it will prompt you to install the userland Canonical packaged for Ubuntu. This takes another while. The whole process takes a lot of time, by the way, so make sure you reserve half a day at least. Don&rsquo;t do it at work :-)</p>
<p>One problem I stumbled upon right away is that networking was not working properly. Someone <a href="https://github.com/microsoft/WSL/issues/35"target="_blank" rel="noopener">narrowed it down</a> to DNS not being added to <tt>/etc/resolv.conf</tt> so you must add it manually. Just add the Google DNS (8.8.8.8 and 8.8.4.4) to the resolv.conf file and you&rsquo;re up.</p>
<p>Finally, you land inside bash as the root user. If you&rsquo;re a Windows user, know right now that running as root is insecure and a bad practice. Don&rsquo;t do it.</p>
<p>The very first thing you <strong>must</strong> do is manually create an unprivileged Linux user and add it to the sudo group as Andrew Malton <a href="https://web.archive.org/web/20160411063840/http://blog.greenarrow.me/elixir-with-ubuntu-for-windows/"target="_blank" rel="noopener">blogged</a> first:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>useradd new_username -m -s /bin/bash 
passwd new_username
usermod -aG sudo new_username</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Then you can log into this user shell with <tt>su - [your user]</tt> every time!</p>
<p>From here, we can assume it&rsquo;s a plain Ubuntu 14.04 and you should be able to follow <a href="http://www.akitaonrails.com/2015/01/28/ruby-e-rails-no-ubuntu-14-04-lts-trusty-tahr"target="_blank" rel="noopener">my very old post</a> on how to setup a developer Ubuntu environment, or any other tutorial you can find over Google. These basic development packages that I always install first all run:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>sudo apt-get install curl build-essential openssl libcurl4-openssl-dev libreadline6 libreadline6-dev curl git-core zlib1g zlib1g-dev libssl-dev libyaml-dev libsqlite3-dev sqlite3 libxml2-dev libxslt-dev libgmp-dev autoconf libc6-dev ncurses-dev automake libtool bison subversion redis-server libhiredis-dev memcached libmemcached-dev imagemagick libmagickwand-dev exuberant-ctags ncurses-term ack-grep git git-svn gitk ssh libssh-dev

sudo dpkg-divert --local --divert /usr/bin/ack --rename --add /usr/bin/ack-grep</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>This should give you all the compilation toolchain essentials as well as some well known command line tools such as ack (way better than grep). It also adds Redis and Memcached. They all run.</p>
<p>As good practice you should add the following to your <tt>/etc/bash.bashrc</tt> configuration file:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>export LANGUAGE=en_US.UTF-8
export LANG=en_US.UTF-8
export LC_ALL=en_US.UTF-8</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>And after that you should also configure locale to UTF-8:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>sudo locale-gen en_US.UTF-8
sudo dpkg-reconfigure locales</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Just to warm up a little bit, we can start with one of the things that were impossible in Windows: getting a stable Ruby installation. For that, RVM is said to not work (as ZSH is also not working due to /dev/pts and symlink problems in this preview, see more below). But RBENV is working! You must <a href="https://github.com/rbenv/rbenv"target="_blank" rel="noopener">install it</a> first and then the <a href="https://github.com/rbenv/ruby-build#readme"target="_blank" rel="noopener">ruby-build</a> plugin:</p>
<p><a href="https://akitaonrails.s3.amazonaws.com/assets/image_asset/image/536/installing_ruby.png"target="_blank" rel="noopener"><img src="https://akitaonrails.s3.amazonaws.com/assets/image_asset/image/536/big_installing_ruby.png" alt="installing ruby through rbenv"  loading="lazy" /></a></p>
<p>Interestingly, it takes a lot of time to complete and during the process CPU usage goes through the roof. Installing Go is even longer! Something is still unstable underneath as it shouldn&rsquo;t take the CPU to 100% for so long.</p>
<p><img src="https://akitaonrails.s3.amazonaws.com/assets/image_asset/image/537/big_resources.jpg" alt="CPU through the roof"  loading="lazy" /></p>
<p>If I check how much memory I have in the system it becomes clearer:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>root@localhost:/mnt/c/Users/fabio# free -h
             total       used       free     shared    buffers     cached
Mem:          1.0G       342M       664M         0B         0B         0B
-/&#43; buffers/cache:       342M       664M
Swap:           0B         0B         0B</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>I am not sure if this is somehow just a &ldquo;hard-coded&rdquo; value for memory as many people are reporting the same &ldquo;664M&rdquo; free regardless of what we are running. But something is incomplete here. Swap is also zero and you can&rsquo;t add any as far as I can tell. Swapon, fallocate, none of those work yet.</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>root@localhost:/mnt/c/Users/fabio# swapon -s
swapon: /proc/swaps: open failed: No such file or directory

root@localhost:/mnt/c/Users/fabio# fallocate -l 4G swapfile
fallocate: swapfile: fallocate failed: Invalid argument</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>I actually tried to <a href="https://www.digitalocean.com/community/tutorials/how-to-add-swap-on-ubuntu-14-04"target="_blank" rel="noopener">create a swap file</a> using <tt>dd</tt> instead of <tt>fallocate</tt> and add it to the <tt>/etc/fstab</tt> but it didn&rsquo;t work:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>root@localhost:/mnt/c/Users/fabio# free -m
             total       used       free     shared    buffers     cached
Mem:          1006        342        664          0          0          0
-/&#43; buffers/cache:        342        664
Swap:            0          0          0

root@localhost:/mnt/c/Users/fabio# cat /etc/fstab
LABEL=cloudimg-rootfs   /        ext4   defaults        0 0
/swapfile       none    swap    sw      0 0</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>So it sounds like memory is &ldquo;hard-coded&rdquo;. Follow <a href="https://github.com/microsoft/WSL/issues/92"target="_blank" rel="noopener">this issue #92</a> if you want to know how it develops.</p>
<p>But worse than that, shared memory has very low limits and strange behavior. Postgresql will install but won&rsquo;t start up at all:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>root@localhost:/mnt/c/Users/fabio# pg_createcluster 9.3 main --start
Creating new cluster 9.3/main ...
  config /etc/postgresql/9.3/main
  data   /var/lib/postgresql/9.3/main
  locale en_US.UTF-8
FATAL:  could not create shared memory segment: Invalid argument
DETAIL:  Failed system call was shmget(key=1, size=48, 03600).
HINT:  This error usually means that PostgreSQL&#39;s request for a shared memory segment exceeded your kernel&#39;s SHMMAX parameter, or possibly that it is less than your kernel&#39;s SHMMIN parameter.
        The PostgreSQL documentation contains more information about shared memory configuration.
child process exited with exit code 1
initdb: removing contents of data directory &#34;/var/lib/postgresql/9.3/main&#34;
Error: initdb failed</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>And if we try to expand the SHMMAX limit this is what we get:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>root@localhost:/mnt/c/Users/fabio# sysctl -w kernel.shmmax=134217728
sysctl: cannot stat /proc/sys/kernel/shmmax: No such file or directory

root@localhost:/mnt/c/Users/fabio# echo 134217728 &gt;/proc/sys/kernel/shmmax
bash: /proc/sys/kernel/shmmax: Operation not permitted</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>So, no Postgresql for the time being. Some people who were able to complete the Go Lang installation (I gave up after a very, very long time waiting for apt-get to finish) complained that Go also crashed on shared memory requirements. Follow <a href="https://github.com/microsoft/WSL/issues/32"target="_blank" rel="noopener">Issue #32</a> and <a href="https://github.com/microsoft/WSL/issues/146"target="_blank" rel="noopener">Issue #146</a> to see if anyone can make it work.</p>
<p>I also tried to install Node.js. No luck with package installs:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>curl -sL https://deb.nodesource.com/setup_5.x | sudo -E bash -
...
E: dpkg was interrupted, you must manually run &#39;sudo dpkg --configure -a&#39; to correct the problem.
Error executing command, exiting</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>NVM installs, sort of, with many errors in git:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>...
error: unable to create file test/slow/nvm run/Running &#34;nvm run 0.x&#34; should work (No such file or directory)
error: unable to create file test/slow/nvm run/Running &#34;nvm run&#34; should pick up .nvmrc version (No such file or directory)
error: unable to create file test/slow/nvm use/Running &#34;nvm use iojs&#34; uses latest io.js version (No such file or directory)
error: unable to create file test/slow/nvm use/Running &#34;nvm use node&#34; uses latest stable node version (No such file or directory)
error: unable to create file test/slow/nvm use/Running &#34;nvm use v1.0.0&#34; uses iojs-v1.0.0 iojs version (No such file or directory)
error: unable to create file test/slow/nvm use/Running &#34;nvm use&#34; calls &#34;nvm_die_on_prefix&#34; (No such file or directory)</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>And this is what happens if I try to install the most recent version:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>akitaonrails@localhost:~/.nvm$ nvm install 5.10.1
Downloading https://nodejs.org/dist/v5.10.1/node-v5.10.1-linux-x64.tar.xz...
######################################################################## 100.0%
tar: bin/npm: Cannot create symlink to &#39;../lib/node_modules/npm/bin/npm-cli.js&#39;: Invalid argument
tar: Exiting with failure status due to previous errors
Binary download failed, trying source.
######################################################################## 100.0%
Checksums empty
tar: bin/npm: Cannot create symlink to &#39;../lib/node_modules/npm/bin/npm-cli.js&#39;: Invalid argument
tar: Exiting with failure status due to previous errors
Binary download failed, trying source.
Detected that you have 1 CPU thread(s)
Number of CPU thread(s) less or equal to 2 will have only one job a time for &#39;make&#39;
Installing node v1.0 and greater from source is not currently supported</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p><a href="https://github.com/microsoft/WSL/issues/9"target="_blank" rel="noopener">Issue #9</a> points to non-implemented symlink support.</p>
<p>Another very annoying thing is the lack of Pseudo-Terminals (/dev/pts), which is possibly one of the reasons ZSH won&rsquo;t work. Follow <a href="https://github.com/microsoft/WSL/issues/80"target="_blank" rel="noopener">Issue #80</a>.</p>
<p>You should also be able to copy over your SSH private keys to &ldquo;.ssh&rdquo; and start git cloning from Github or git push-ing to Heroku in no time.</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>akitaonrails@localhost:~$ ssh-keygen  -t rsa
Generating public/private rsa key pair.
Created directory &#39;/home/akitaonrails/.ssh&#39;.kitaonrails/.ssh/id_rsa):
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /home/akitaonrails/.ssh/id_rsa.
Your public key has been saved in /home/akitaonrails/.ssh/id_rsa.pub.
The key fingerprint is:
f8:16:b1:be:85:31:0c:71:f8:c2:d3:72:ab:48:42:9a akitaonrails@localhost
The key&#39;s randomart image is:
&#43;--[ RSA 2048]----&#43;
|      ...        |
|      .o         |
|     ..o.        |
|  .   =&#43;&#43;o       |
| &#43;    .=S.       |
|E . .  o.=       |
|   o . .= .      |
|    . .. o       |
|        .        |
&#43;-----------------&#43;</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>At least, Elixir does seem to work:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>akitaonrails@localhost:~$ iex
Erlang/OTP 18 [erts-7.3] [source-d2a6d81] [64-bit] [async-threads:10] [hipe] [kernel-poll:false]

Interactive Elixir (1.2.3) - press Ctrl&#43;C to exit (type h() ENTER for help)
iex(1)&gt; defmodule HelloWorld do; def say(name) do; IO.puts(&#34;Hello #{name}&#34;); end; end
iex:1: warning: redefining module HelloWorld
{:module, HelloWorld,
 &lt;&lt;70, 79, 82, 49, 0, 0, 5, 240, 66, 69, 65, 77, 69, 120, 68, 99, 0, 0, 0, 147, 131, 104, 2, 100, 0, 14, 101, 108, 105, 120, 105, 114, 95, 100, 111, 99, 115, 95, 118, 49, 108, 0, 0, 0, 4, 104, 2, ...&gt;&gt;,
 {:say, 1}}
iex(2)&gt; HelloWorld.say(&#34;Fabio&#34;)
Hello Fabio
:ok</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Not so fast&hellip;</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>akitaonrails@localhost:~$ mix new ex_test
** (ErlangError) erlang error: :terminated
    (stdlib) :io.put_chars(#PID&lt;0.25.0&gt;, :unicode, [[[[[[[] | &#34;\e[32m&#34;], &#34;* creating &#34;] | &#34;\e[0m&#34;], &#34;.gitignore&#34;] | &#34;\e[0m&#34;], 10])
    (mix) lib/mix/generator.ex:26: Mix.Generator.create_file/3
    (mix) lib/mix/tasks/new.ex:76: Mix.Tasks.New.do_generate/4
    (elixir) lib/file.ex:1138: File.cd!/2
    (mix) lib/mix/cli.ex:58: Mix.CLI.run_task/2</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>You will find more information on the pseudo-project Microsoft opened over Github to keep track of <a href="https://github.com/microsoft/WSL/issues?q=is%3Aissue&#43;is%3Aclosed"target="_blank" rel="noopener">Issues</a> from testers like me. You can follow the list of opened and closed issues there. You will see many things that work, but also many other things that won&rsquo;t work until a new release is available to fix everything I mentioned here.</p>
<h3>Conclusion<span class="hx:absolute hx:-mt-20" id="conclusion"></span>
    <a href="#conclusion" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>So, is &ldquo;Bash on Windows&rdquo; a good development environment for Linux users to have over Windows?</p>
<p>As far as Preview 14316, not yet. The keyword here is &ldquo;yet&rdquo;. It&rsquo;s shaping up nicely, and if they can actually fix all the issues opened so far, it will be very usable very fast.</p>
<p>We still need decent memory controls, well-implemented pseudo-terminal support, configurable shared memory limits, and working symlinks. We also need Ubuntu&rsquo;s upstart, so services like Redis or Memcached (which I installed and run) come up on their own when I start the environment. Right now they don&rsquo;t come back after I reboot the machine.</p>
<p><a href="http://www.neowin.net/news/bash-plus-windows-10-equals-linux-gui-apps-on-the-windows-desktop"target="_blank" rel="noopener">Some people</a> went as far as being able to trick X11 and run GUI apps such as Firefox and even XFCE over this environment already, so it&rsquo;s really promising. This idea does work.</p>
<p>Once those issues are ironed out, yes, I believe we are closer than ever to finally using Windows as a viable and full-featured development environment. Let&rsquo;s see if by the Windows 10 Anniversary Release in June we will have a stable Ubuntu installation.</p>
<p>One thing that I think they did very wrong was to tie the Linux Subsystem to the Windows 10 installation. It should&rsquo;ve been a separate installer, so the team could release build updates without having to bundle it all together with the entire Windows OS.</p>
<p>If you were intending to move to Windows for your Linux-based developments, not yet. Hold your horses a bit longer.</p>
]]></content:encoded><category>microsoft</category><category>linux</category><category>developer-tools</category><category>off-topic</category></item><item><title>War is Over, or is it? A New Dawn for Microsoft</title><link>https://akitaonrails.github.io/en/2016/03/31/war-is-over-or-is-it-a-new-dawn-for-microsoft/</link><guid isPermaLink="true">https://akitaonrails.github.io/en/2016/03/31/war-is-over-or-is-it-a-new-dawn-for-microsoft/</guid><pubDate>Thu, 31 Mar 2016 18:02:00 -0300</pubDate><description>&lt;p&gt;Update 04/07: &lt;a href="http://thehackernews.com/2016/04/how-to-run-ubuntu-on-windows-10.html"target="_blank" rel="noopener"&gt;the preview is already out&lt;/a&gt; ahead of the June release. If you&amp;rsquo;re an Insider member, try it. Leave your impressions in the comments.&lt;/p&gt;
&lt;p&gt;Yesterday was a historic day for Microsoft. From my personal perspective, it may have been a watershed. Ever since, I&amp;rsquo;ve been trying to figure out how to register the moment for posterity.&lt;/p&gt;
&lt;h3&gt;Prologue - 1995 to 2005, the 1st Decade&lt;span class="hx:absolute hx:-mt-20" id="prologue---1995-to-2005-the-1st-decade"&gt;&lt;/span&gt;
&lt;a href="#prologue---1995-to-2005-the-1st-decade" class="subheading-anchor" aria-label="Permalink for this section"&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;I mean this for us, software developers. We&amp;rsquo;ve been through moments like this before: the release of Turbo Pascal in 1983, Visual Basic in 1991, Java in 1995, the first Linux distros like Slackware from 1993 on, the release of OS X in 2000, and the PowerPC-to-Intel transition in 2005.&lt;/p&gt;</description><content:encoded><![CDATA[<p>Update 04/07: <a href="http://thehackernews.com/2016/04/how-to-run-ubuntu-on-windows-10.html"target="_blank" rel="noopener">the preview is already out</a> ahead of the June release. If you&rsquo;re an Insider member, try it. Leave your impressions in the comments.</p>
<p>Yesterday was a historic day for Microsoft. From my personal perspective, it may have been a watershed. Ever since, I&rsquo;ve been trying to figure out how to register the moment for posterity.</p>
<h3>Prologue - 1995 to 2005, the 1st Decade<span class="hx:absolute hx:-mt-20" id="prologue---1995-to-2005-the-1st-decade"></span>
    <a href="#prologue---1995-to-2005-the-1st-decade" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>I mean this for us, software developers. We&rsquo;ve been through moments like this before: the release of Turbo Pascal in 1983, Visual Basic in 1991, Java in 1995, the first Linux distros like Slackware from 1993 on, the release of OS X in 2000, and the PowerPC-to-Intel transition in 2005.</p>
<p>The 80s and 90s were convoluted, an era of accelerated growth where everything went obsolete fast. In one decade, from 1989 to 1999, I went from Basic to dBase, Clipper, Fox Pro, Visual Basic, Delphi, Java, multimedia (Flash, Director/Shockwave), and the Internet (HTML, Javascript, ASP, PHP, Perl). I&rsquo;ve never seen a decade move so fast. I went from a 4 MHz XT to a Pentium III at almost 1 GHz in those ten years.</p>
<p>We reached the end of the century at the peak of the Internet Bubble, had 9/11 in 2001 and the crash. But the Internet came to stay, and personal devices started showing up with the Palms and iPods. In 2001 Microsoft launched Windows XP and would spend the next decade carrying that legacy on its back.</p>
<p>A year earlier, the small Apple had started its comeback with the new iMac, iBook, and iPod, plus the BSD-UNIX-based OS X. One step at a time, it was building a system meant for both consumers and developers, the NeXT promise taking shape a decade after its inception.</p>
<p>Then, in 2005, Apple forged an alliance with one of Microsoft&rsquo;s oldest partners, Intel, and Macs would finally run on the same processor as Windows, a stratospheric leap in adoption. And that opened another door: since OS X was built processor-agnostic, it was a matter of time before it ran on smaller, more efficient ARM chips. That&rsquo;s what happened in 2007 with the iPhone. The rest is history.</p>
<h3>2005 to 2015 - 2nd Decade<span class="hx:absolute hx:-mt-20" id="2005-to-2015---2nd-decade"></span>
    <a href="#2005-to-2015---2nd-decade" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Meanwhile, Microsoft fell behind. It failed the Windows Vista promise, shipped a competent Windows 7, and followed it with the controversial Windows 8. Only with Windows 10, unveiled at the end of 2014, did things start to change. And the effects of Steve Jobs&rsquo;s death, at the end of 2011, were getting more obvious: Apple had stopped.</p>
<p>From 2011 to today, all we got were new versions. Nothing significant, nothing new. The last big iPhone was the 5, from 2012. The last big OS X feline was Mountain Lion, from 2011. In the meantime Google pulled ahead in mobile when KitKat shipped in 2013, in my view the first Android release on equal footing with iOS.</p>
<p>From 1999 to 2005, broadly, the enterprise software developer had two options: Java and .NET. PHP had solid adoption, but mostly for customizing Wordpress and Magento, far from the same league as Java or .NET; the rest was niche. From 2006 on, a new generation of developers rose for the so-called Web 2.0, the post-Google world of SEO, UX, fast iterations, and Agility with a capital &ldquo;A&rdquo;. That&rsquo;s where Ruby, Python, and then Node took off exponentially.</p>
<p>From 2010, the mobile world sped up, and one kind of integrated development in particular: the &ldquo;Cloud&rdquo; variety, where a native &ldquo;app&rdquo; talks to services on remote servers, mostly Amazon AWS, which had debuted not long before, in 2006.</p>
<p>Microsoft stayed out of that move and spent the next ten years playing catch-up, nursing the Vista hangover. It kept its lead in purely enterprise markets, with SQL Server and Office licenses, but on the margins of cutting-edge software development.</p>
<p>Actually, I&rsquo;d say the watershed came in 2013, with <a href="http://web.archive.org/web/20160404073120/http://olhardigital.uol.com.br/pro/noticia/mercado-reage-bem-a-saida-de-ballmer-da-microsoft/36992"target="_blank" rel="noopener">Ballmer&rsquo;s exit</a> and the end of the &ldquo;Extended Gates Era&rdquo;, opening the door for <a href="http://www.businessinsider.com/microsoft-year-in-review-2015-12"target="_blank" rel="noopener">Satya Nadella to step in</a>. Microsoft is a giant, plenty of its brains had been researching this for years, and a lot of it only surfaced now. But I mean &ldquo;Eras&rdquo; in a symbolic sense: the end of Microsoft&rsquo;s Highlander culture, the &ldquo;there can only be one&rdquo;.</p>
<p>The <a href="http://1995blog.com/2015/05/24/the-internet-tidal-wave-20-years-on/"target="_blank" rel="noopener">1995 prophecy</a> that the Internet would destroy the Windows hegemony came true. And we reached the post-Moore world, where computing became accessible and ubiquitous. Think about it: in 1995, having a cluster of &ldquo;super&rdquo; computers for high-throughput distributed computing was for universities or big corporations. Today, you spin up a cluster of as many dozens of machines as you want on EC2 for a month at the price of a video game console.</p>
<p>I was a DOS user from 1988, switched to Windows 95 as soon as it launched, and spent almost ten years developing primarily on Windows, in the corporate world. I went from Visual Basic to ASP to .NET while also doing Java and PHP. But I wanted to run Perl, PHP, Python, and Ruby native on Linux, without giving up Office and Photoshop.</p>
<p>The answer we were waiting for was OS X. With the release of Tiger, things got serious. I tried it myself on a Mac Mini G4 in 2004. It was exceptional to have usability far better than Windows XP and access to all the UNIX I wanted on a single machine.</p>
<p>When Intel launched the Core Duo and then the 64-bit Core 2 Duo, and Tiger started running on Intel in 2005, there was nothing to think about: it was time to migrate. I&rsquo;d spend the next decade in a pure OS X environment, developing on a different kind of platform, with different tools and a different culture. That was my whole story with Ruby and OS X over these ten years, which you know well if you follow this blog.</p>
<h3>2015 on forward, Epilogue<span class="hx:absolute hx:-mt-20" id="2015-on-forward-epilogue"></span>
    <a href="#2015-on-forward-epilogue" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>2015 arrived, four years after Steve Jobs&rsquo;s death. It was an important gap, because it gave the non-Mac platforms time to catch up and surpass OS X in many areas. We&rsquo;re firmly in the Software as a Service Era. We don&rsquo;t &ldquo;buy&rdquo; anything anymore, we &ldquo;subscribe&rdquo; to services.</p>
<p>We&rsquo;re past the Post-PC Era. We&rsquo;re past the Smartphone Era. We&rsquo;re in the Services Era, where everything is a service. Our identity is a Facebook profile, our voice is WhatsApp, and everything we do generates data. We&rsquo;re in the Big Data Era, a pile of useless data that no SQL Server in the world can keep up with.</p>
<p>We need new things to handle this paradigm: Cassandra, Riak, Hadoop, HBase, Spark, Elasticsearch, Go, Rust, Elixir. They all &ldquo;run&rdquo; on Windows, but someone has to spend time doing ports, writing compatibility patches, and packaging installers. And the main thing: most of the developers behind these technologies are on Linux or OS X, almost nobody builds this new generation of tools inside Windows. They all use Emacs, Vim, or Sublime Text, hardly anyone wants Visual Studio.</p>
<p>And this brings me back to the start of the post: it&rsquo;s a new Era for Microsoft. It spent the last ten years playing catch-up and, for the first time, it looks like it has a real shot at turning things around and becoming relevant to the non-.NET developer again.</p>
<p>For that, two things happened yesterday.</p>
<h3>2016 - The Year of Linux on the Desktop<span class="hx:absolute hx:-mt-20" id="2016---the-year-of-linux-on-the-desktop"></span>
    <a href="#2016---the-year-of-linux-on-the-desktop" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>First, the announcement that <a href="http://thehackernews.com/2016/03/ubuntu-on-windows-10.html"target="_blank" rel="noopener">&ldquo;Bash is coming to Windows&rdquo;</a>. Which in practice is much more than Bash: it&rsquo;s a partnership with Canonical, one that had been taking shape since the announcement of <a href="http://web.archive.org/web/20160415160138/http://www.microsoft.com/en/server-cloud/sql-server-on-linux.aspx"target="_blank" rel="noopener">SQL Server running on Linux</a>. In practice, it&rsquo;s a <a href="http://blog.dustinkirkland.com/2016/03/ubuntu-on-windows.html"target="_blank" rel="noopener">Linux subsystem</a> running alongside the Windows kernel, translating Linux syscalls into Windows syscalls.</p>
<p>The original idea came from the deceased Project Astoria, or Windows Bridge for Android, which back then wanted to let Android apps run on Windows. Technically, Android is a flavor of Linux, so the jump to yesterday was a short one.</p>
<p>So it&rsquo;ll be possible to take a binary built for Ubuntu and run it on Windows without changing a thing.</p>
<p>Ever since we started developing with Ruby, a lot of Windows users wanted to run Ruby natively. There&rsquo;s a <a href="http://rubyinstaller.org/"target="_blank" rel="noopener">distribution</a>, but it&rsquo;s not good, and that&rsquo;s not the maintainers&rsquo; fault. Ruby, like Python and PHP, was built to work on Linux.</p>
<p>To port it to Windows you have to write &ldquo;wrappers&rdquo;, and you still lack an environment with compilers like GCC to build extension packages. All of that is trivial on Linux and a headache on Windows. It wasn&rsquo;t worth the trouble, so the only way out was to run a virtual machine (like VirtualBox) with something like Vagrant to make it easier and use the real Linux Ruby.</p>
<p>Everything from Linux that &ldquo;works&rdquo; on Windows, whether Python or PHP, never worked 100%, and we just got used to it.</p>
<p>What Microsoft is shipping in the Anniversary Update is a very thin translation layer at the lowest level, and not a virtual machine or a hypervisor: from a &ldquo;virtual&rdquo; Linux kernel to the Windows kernel. Everything will think it&rsquo;s running on Linux. It&rsquo;s what the Wine project tries to do to run Windows applications on Linux, only in reverse. It&rsquo;s also different from Cygwin, which requires recompiling everything from Linux to get a semi-Linux environment on top of Windows.</p>
<p>There probably won&rsquo;t be a secondary graphical environment at first, so no X, no GNOME or KDE. And there&rsquo;s no need: we&rsquo;re in a Web world, our graphical environment now is HTML and Javascript, and Chrome and Firefox already run native on Windows. For things like compiling gems with native extensions, even GCC will work. It&rsquo;s the exact same binary, in the same environment, with everything we&rsquo;re used to on UNIX. Having Bash and SSH on Windows is just the tip of the iceberg.</p>
<p>The second announcement is the <a href="http://techcrunch.com/2016/03/31/thanks-to-microsoft-small-teams-can-now-get-xamarins-ide-and-core-tools-for-free"target="_blank" rel="noopener">release of the Xamarin tools for free and as open source</a>! Microsoft acquired Xamarin, Miguel de Icaza&rsquo;s company, not long ago. They built open-source .NET through pure reverse engineering, reimplementing everything as open source, and now Microsoft did the smart thing: on top of buying them, it opened the tools. The last thing still keeping a developer on the Mac was needing Xcode, which ships with OS X, to develop for iOS. Now you can do that on Windows for free.</p>
<p>So the math got much simpler. Windows 10 is the first respectable Windows version since the brief window of 7. Let&rsquo;s forget Windows 8 existed, the same way we already forgot Vista. XP is finally dead, it took over a decade, along with the hideous Internet Explorer 6, 7, and 8. Google did us the favor of making Chrome ubiquitous, and services like Facebook forced users to migrate faster.</p>
<p>With the <a href="http://arstechnica.com/information-technology/2016/03/windows-10-270-million-users-binbash-supporting-anniversary-update-coming-summer/"target="_blank" rel="noopener">Windows 10 Anniversary Update</a>, we&rsquo;ll probably be able to do:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>apt-get install build-essential
\curl -sSL https://get.rvm.io | bash
rvm install 2.3.0
bundle install</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>And it should just work.</p>
<p>In the same environment, we&rsquo;ll still be able to use Xamarin Studio and, with a little effort to jog the C# muscle memory, build iOS and Android apps. We&rsquo;ll be able to use native Office 365, all the latest Adobe CS6 tools, and even play The Division, all on the same machine.</p>
<p>In one shot, Windows 10 becomes the best value choice: convenience of use, development options, and competent hardware in the form of the Surface Book, Lenovo Yoga 3, and Razer Blade Stealth, which finally caught up to and passed the legendary finish of the MacBook.</p>
<p>2016 is finally the infamous Year of Linux on the Desktop, just not the way the Free Software crowd wanted. You can&rsquo;t have everything.</p>
]]></content:encoded><category>microsoft</category><category>developer-tools</category><category>tech-market</category><category>off-topic</category></item><item><title>[Off-Topic] Reading with subtitles over Kanjis in Japanese webpages</title><link>https://akitaonrails.github.io/en/2012/05/08/off-topic-reading-with-subtitles-over-kanjis-in-japanese-webpages/</link><guid isPermaLink="true">https://akitaonrails.github.io/en/2012/05/08/off-topic-reading-with-subtitles-over-kanjis-in-japanese-webpages/</guid><pubDate>Tue, 08 May 2012 10:36:00 -0300</pubDate><description>&lt;p&gt;This is something I just stumbled upon and because it&amp;rsquo;s tricky to install the first time I decided to grab the pieces that make it work. It&amp;rsquo;s so useful I had to post about it.&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;re learning Japanese this will definitely prove to be an invaluable tool. I am Japanese but I didn&amp;rsquo;t pay attention to proper Kanji training when I was a child. It shows now, as I can read Kanji only to what would be considered below high-school level in Japan. Still very useful, but it means I can&amp;rsquo;t read most websites in Japanese fast enough.&lt;/p&gt;</description><content:encoded><![CDATA[<p>This is something I just stumbled upon and because it&rsquo;s tricky to install the first time I decided to grab the pieces that make it work. It&rsquo;s so useful I had to post about it.</p>
<p>If you&rsquo;re learning Japanese this will definitely prove to be an invaluable tool. I am Japanese but I didn&rsquo;t pay attention to proper Kanji training when I was a child. It shows now, as I can read Kanji only to what would be considered below high-school level in Japan. Still very useful, but it means I can&rsquo;t read most websites in Japanese fast enough.</p>
<p>I&rsquo;ve known of a Firefox add-on I&rsquo;m very fond of for a long time now called <a href="http://web.archive.org/web/20120624074033/https://addons.mozilla.org/pt-br/firefox/addon/rikaichan/"target="_blank" rel="noopener">Rikaichan</a>. When enabled, you hover your mouse over the kanji text and it will popup a box with the translation. You install the Firefox add-on in the previous link and a proper dictionary to your native language from <a href="http://web.archive.org/web/20120512063523/http://polarcloud.com/rikaichan"target="_blank" rel="noopener">Rikaichan&rsquo;s webpage</a>. And that&rsquo;s it.</p>
<p><img src="http://s3.amazonaws.com/akitaonrails/assets/2012/5/8/Screen%20Shot%202012-05-08%20at%2010.30.34%20AM_original.png?1336483998" alt=""  loading="lazy" /></p>
<p>But if you like to read Manga (Japanese Comics), you&rsquo;re probably familiar with Furigana. It&rsquo;s kind of like &ldquo;subtitling&rdquo; over the Kanjis with Hiragana or Katakana, the Japanese syllabaries (the first for Japanese only words, the second for foreign words).</p>
<p>That makes reading the more difficult Kanjis way easier and faster than hovering over each one or looking manually into the dictionary ideogram by ideogram.</p>
<p>A normal snippet of a Japanese webpage looks like this:</p>
<p><img src="http://s3.amazonaws.com/akitaonrails/assets/2012/5/8/Screen%20Shot%202012-05-08%20at%2010.17.14%20AM_original.png?1336483852" alt=""  loading="lazy" /></p>
<p>But with <a href="http://web.archive.org/web/20131115215917/https://addons.mozilla.org/pt-BR/firefox/addon/furigana-inserter/"target="_blank" rel="noopener">Furigana Inserter</a> the same snippet looks like this:</p>
<p><img src="http://s3.amazonaws.com/akitaonrails/assets/2012/5/8/Screen%20Shot%202012-05-08%20at%2010.17.25%20AM_original.png?1336483884" alt=""  loading="lazy" /></p>
<p>To install it, first you install the <a href="http://web.archive.org/web/20131115215917/https://addons.mozilla.org/pt-BR/firefox/addon/furigana-inserter/"target="_blank" rel="noopener">add-on</a>. Then you install the <a href="http://web.archive.org/web/20130501123822/https://addons.mozilla.org/en-US/firefox/addon/html-ruby/"target="_blank" rel="noopener">HTML Ruby</a> add-on as well. Finally, you install this <a href="http://web.archive.org/web/20111115202242/http://code.google.com:80/p/itadaki/downloads/detail?name=furiganainserter-dictionary-1.2.7z"target="_blank" rel="noopener">dictionary</a>. It&rsquo;s a 7-zip file you must decompress and manually drag it over Firefox to install.</p>
<p>If you&rsquo;re on a Mac, I&rsquo;m assuming you know what <a href="https://github.com/mxcl/homebrew"target="_blank" rel="noopener">Homebrew</a> is and already have that installed. Because then you can install Mecab like this:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">brew install mecab
</span></span><span class="line"><span class="cl">brew install mecab-ipadic</span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Finally, it seems like you must manually make Furigana Inserter aware of Mecab by adding a symlink into its extension folder:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">ln -s /usr/local/lib/libmecab.dylib ~/Library/Application<span class="se">\ </span>Support/Firefox/Profiles/454dy2eg.default/extensions/furiganainserter@zorkzero.net/mecab/libmecab.dylib</span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Understand that the Firefox Profile folder will have a different name on your computer. The one in the example is in my Mac. Open the terminal and tab to autocomplete each folder as you type and it should work just fine.</p>
<p>Restart Firefox, right-click in Japanese pages and you will have an &ldquo;Enable Furigana&rdquo; option waiting for you. Rikaichan seems to misbehave when hovering over Furigana enabled Kanji, so you may need to disable Furigana to use Rikaichan. But it&rsquo;s a good compromise and may open a whole lot of new content in Japanese for us to consume.</p>
<p>One more reason to use Firefox.</p>
]]></content:encoded><category>learning</category><category>developer-tools</category><category>off-topic</category></item><item><title>[Off-Topic] Bought My First Mac — Now What?</title><link>https://akitaonrails.github.io/en/2009/07/19/off-topic-comprei-meu-primeiro-mac-e-agora/</link><guid isPermaLink="true">https://akitaonrails.github.io/en/2009/07/19/off-topic-comprei-meu-primeiro-mac-e-agora/</guid><pubDate>Sun, 19 Jul 2009 22:01:00 -0300</pubDate><description>&lt;p&gt;&lt;strong&gt;Update 04/20/2012:&lt;/strong&gt; This is one of the most-read articles on my blog, first published in 09/2009. Most of the article still holds up well today, so I decided to adjust a few things and add more current information. If you&amp;rsquo;ve already read this article and want to see only what I added, check &lt;a href="http://akitaonrails.com/2012/04/20/off-topic-comprei-meu-primeiro-mac-e-agora-edicao-2012"target="_blank" rel="noopener"&gt;this post&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;You&amp;rsquo;re a &amp;ldquo;switcher&amp;rdquo;: you&amp;rsquo;ve decided to take the big leap, step away from the Windows world a bit, and buy your first Mac. The timing is good and prices are accessible, especially if you can buy from someone abroad. Keep one thing in mind from the start: this is a paradigm shift.&lt;/p&gt;</description><content:encoded><![CDATA[<p><strong>Update 04/20/2012:</strong> This is one of the most-read articles on my blog, first published in 09/2009. Most of the article still holds up well today, so I decided to adjust a few things and add more current information. If you&rsquo;ve already read this article and want to see only what I added, check <a href="http://akitaonrails.com/2012/04/20/off-topic-comprei-meu-primeiro-mac-e-agora-edicao-2012"target="_blank" rel="noopener">this post</a>.</p>
<p>You&rsquo;re a &ldquo;switcher&rdquo;: you&rsquo;ve decided to take the big leap, step away from the Windows world a bit, and buy your first Mac. The timing is good and prices are accessible, especially if you can buy from someone abroad. Keep one thing in mind from the start: this is a paradigm shift.</p>
<p>The first week or two are the worst. You&rsquo;ll always have that nagging thought, <em>&ldquo;On Windows I did this more easily…&rdquo;</em> or <em>&ldquo;On my Linux I did this more easily…&rdquo;</em>. The temptation to go back is strong the first time you leave your comfort zone, same as with any change. Push yourself to learn the new tricks instead of falling back on the old ones.</p>
<p><img src="http://s3.amazonaws.com/akitaonrails/assets/2009/7/20/overview-gallery1-20090608_original.png" alt=""  loading="lazy" /></p>
<p>As soon as you log in to the Mac for the first time, it arrives in a state where you need to configure very little. A few important things to get you started:</p>
<ul>
<li>The first difference is that application menus are all centralized. The bar at the top is the only menu, and it changes according to the application that currently has focus. The first option is the  icon, which gives access to global system options like &ldquo;About,&rdquo; where you can view details of your hardware; &ldquo;Software Update,&rdquo; the equivalent of Windows Update; and options like Shutdown. By the way, the very first thing to do when starting your Mac is to run Software Update and install the latest updates. Unlike Windows, you tend to get large packages rather than dozens of small updates.</li>
</ul>
<p><img src="http://s3.amazonaws.com/akitaonrails/assets/2009/7/21/Picture_16_original.png" alt=""  loading="lazy" /></p>
<ul>
<li>
<p>The second option is always the name of the focused application. Initially it will always be &ldquo;Finder,&rdquo; the equivalent of Windows Explorer. This menu always gives access to things like &ldquo;Preferences,&rdquo; which on Windows usually lives under the &ldquo;Edit&rdquo; or &ldquo;Tools&rdquo; menus.</p>
</li>
<li>
<p>Some shortcuts are global and constant. To start, understand that there is the Ctrl (control, as on a PC) key and a special one called Command ⌘. They are different, and although it isn&rsquo;t a strict rule, things done on a PC with Ctrl are done on a Mac with ⌘. For example, copying text to the clipboard is ⌘+C, not Ctrl+C. Pasting is ⌘+V. Every application closes with ⌘+Q. The &ldquo;Preferences&rdquo; option is always ⌘+, (comma). The &ldquo;Help&rdquo; menu is always ⌘+Shift+?. A tip on that last Help option: use it to discover menu items whose shortcut you don&rsquo;t remember or whose submenu you can&rsquo;t find. Just type a few letters and Mac OS will open the menu and highlight the right item for you.</p>
</li>
<li>
<p>Unlike Windows, the Mac paradigm is based on one window per document rather than a single application window with embedded document windows. ⌘+W closes the application&rsquo;s current window. ⌘+N or ⌘+Shift+N usually opens a new window. We don&rsquo;t normally close applications very often; they tend to stay open. That&rsquo;s indicated in the Dock, at the bottom of the screen, by a glowing circle below the icon of an open application.</p>
</li>
<li>
<p>Also unlike Windows windows, the red circle at the top of each window closes only that window, not the entire application. It&rsquo;s the equivalent of ⌘+W. Another thing: you can move a window from the title bar or the footer bar, when there is one. So even if a window is partly off the physical desktop, you can still move it. On the other hand, the only way to resize a window is from the lower-right corner, not from any edge.</p>
</li>
</ul>
<p><img src="http://s3.amazonaws.com/akitaonrails/assets/2009/7/20/Picture_3_original.png" alt=""  loading="lazy" /></p>
<ul>
<li>
<p>In the title bar of applications that manipulate files, like Finder, Pages, and most apps that show the filename with an icon next to it, the icon is &ldquo;normally&rdquo; draggable. You can drag it to a folder and the file being edited moves there. You can also click while holding ⌘ (Command) and it will show the parent folders, letting you navigate them.</p>
</li>
<li>
<p>Another thing that doesn&rsquo;t exist on Windows: &ldquo;Hide Windows.&rdquo; Get used to ⌘-H to hide all windows of an application. It isn&rsquo;t the same as minimizing, since hidden windows don&rsquo;t appear in the Dock. A hidden application keeps a transparent icon in the Dock. Even better: if you have dozens of applications open in a mess of windows behind windows, use ⌘-⌥-H (Command-Option-H) to hide every window except the one currently in focus. It&rsquo;s a very satisfying way to clean up your workspace and focus on what you&rsquo;re doing.</p>
</li>
<li>
<p>To switch between applications, on Windows we&rsquo;re used to Alt-Tab. On the Mac the near equivalent is ⌘-Tab. But it switches between Applications, not between Windows like on Windows. It&rsquo;s a subtle difference. If you have Photoshop with 4 windows and Word with 3 windows open, ⌘-Tab shows only 2 icons, one per application. To switch between windows of the same application, use ⌘-` (Command-Backtick). Or, more commonly, use Exposé to pick between windows.</p>
</li>
</ul>
<p><img src="http://s3.amazonaws.com/akitaonrails/assets/2009/7/21/Picture_17_original.png" alt=""  loading="lazy" /></p>
<ul>
<li>
<p>Note the icons on the F1 through F12 keys; they clearly show the functions you get when you press them. F1 and F2 are screen brightness. F3 is Exposé. F4 is the Dashboard, where you install Widgets. F11 and F12 are volume. Those are the main ones. Don&rsquo;t forget that on newer MacBooks with a Multitouch Trackpad you have options like swiping 4 fingers down to activate Exposé or up to show the Desktop.</p>
</li>
<li>
<p>Spotlight is very useful. ⌘+Space activates the search field. If you use external hard drives or USB drives and don&rsquo;t want to waste time indexing their files, open &ldquo;System Preferences,&rdquo; option &ldquo;Spotlight,&rdquo; and drag the volumes that should be excluded.</p>
</li>
</ul>
<p><img src="http://s3.amazonaws.com/akitaonrails/assets/2009/7/20/Picture_5_original.png" alt=""  loading="lazy" /></p>
<ul>
<li>
<p>If you&rsquo;re used to Explorer, you&rsquo;ll miss a lot of things in Finder. You can copy and paste folders and files, but there&rsquo;s no cut. You move items to different volumes by dragging and dropping while holding ⌘. To force a copy, use the Option/Alt (⌥) key. You&rsquo;ll end up using drag-and-drop far more than on Windows. You also get different ways to organize your files, especially since ⌘+I opens the Info window, where you can add metadata like keywords for searching and colors (yes, you can even search for files and folders by color in Spotlight).</p>
</li>
<li>
<p>Another difference between Finder and Explorer is how you rename files and run programs. In Explorer you press &ldquo;Enter&rdquo; to run a file and a single mouse click to rename. On the Mac you press &ldquo;Enter&rdquo; to edit the name of a file or folder and ⌘+O to run a program. That avoids the situation where you select dozens of files, accidentally hit Enter, and set off a cascade of programs opening. On the Mac that accident basically never happens.</p>
</li>
<li>
<p>The Dock gives you quick access to your favorite applications. You can drag an icon out to remove it, or drag anything onto it to add it. If you open an application that wasn&rsquo;t there, its icon appears anyway, because the Dock also shows every running application, with a glowing indicator below it. To keep an application in the Dock, drag it there or, while it&rsquo;s open, use the context menu (right-click) on its icon and choose &ldquo;Keep in Dock.&rdquo; If you want that application to launch every time you log in, use &ldquo;Open at Login.&rdquo;</p>
</li>
<li>
<p>Mac OS Leopard (10.5) doesn&rsquo;t ship with the US International keyboard layout that&rsquo;s common on Windows for non-ABNT-2 keyboards (which lack the cedilla). The Mac default is to use shortcuts like ⌥+c for cedilla, ⌥+e for acute accent, ⌥+` for grave accent, ⌥+n for tilde. But if you want the traditional way, download the US International layout for Mac from Brazilian developer <a href="http://web.archive.org/web/20090802092433/http://www.brockerhoff.net/usi/"target="_blank" rel="noopener">Rainer Brokerhoff&rsquo;s</a> site and follow his instructions. From Snow Leopard (10.6) onward, this is no longer necessary.</p>
</li>
<li>
<p>As on Windows and other systems, the Mac&rsquo;s default key repeat rate is somewhat slow. Open any text editor and use the arrow keys to move the cursor and you&rsquo;ll notice the lag. I prefer maximum speed. Go to &ldquo;System Preferences, Keyboard&rdquo; and set &ldquo;Key Repeat&rdquo; to &ldquo;Fast&rdquo; and &ldquo;Delay Until Repeat&rdquo; to &ldquo;Short.&rdquo; You&rsquo;ll thank me:</p>
</li>
</ul>
<p><img src="http://s3.amazonaws.com/akitaonrails/assets/2012/4/20/Screen%20Shot%202012-04-20%20at%206.02.32%20PM_original.png?1334956028" alt=""  loading="lazy" /></p>
<ul>
<li>Say you have hundreds of files, like photos from your digital camera, sitting in JPG, and you want to rename them all to another convention and convert them from JPG to PNG. You can do this and much more with a feature called &ldquo;Automator.&rdquo; In Finder, select the files, right-click (on the Trackpad, place two fingers in the middle and use your thumb to click once at the bottom), then choose &ldquo;More,&rdquo; &ldquo;Automator,&rdquo; &ldquo;Create Workflow.&rdquo; That opens the selected items in Automator, a linear flow of &ldquo;filters&rdquo; where you chain the output of one filter as input to the next, like &ldquo;Change Type of Images,&rdquo; then &ldquo;Rename Finder Items,&rdquo; and even &ldquo;Add attachments to Front Messages,&rdquo; and so on. It&rsquo;s an extremely powerful way to chain actions, a lot like Unix/Linux command-line pipes, but far more intuitive.</li>
</ul>
<p><img src="http://s3.amazonaws.com/akitaonrails/assets/2009/7/20/Picture_6_original.png" alt=""  loading="lazy" /></p>
<ul>
<li>
<p>Few people figure out how to take screenshots at first, since there&rsquo;s no &ldquo;Print Screen&rdquo; key on a Mac. But there&rsquo;s something far better: ⌘+Shift+3 takes a full-screen shot and saves it as a PNG on your Desktop. If you don&rsquo;t want the file, ⌘+Ctrl+Shift+3 sends the shot to the clipboard so you can paste it into another application. Even more useful, ⌘+Shift+4 turns your cursor into a crosshair for capturing just the small area you select. Position the crosshair over any window and press &ldquo;Space&rdquo; and it captures that whole window. For clipboard-only, use ⌘+Ctrl+Shift+4.</p>
</li>
<li>
<p>Another important thing: every print dialog opens with ⌘+P, and it always has the option to generate a PDF instead of sending to a printer. That&rsquo;s extremely useful if you don&rsquo;t have a printer or want to save a receipt from the web or something like that. Beyond that, the &ldquo;Preview&rdquo; application that opens images and PDFs can also do simple editing: resizing images, cropping, copying pages between PDF files, reordering pages, deleting pages. In other words, PDFs are quite editable on a Mac without a commercial Adobe product.</p>
</li>
</ul>
<p><img src="http://s3.amazonaws.com/akitaonrails/assets/2009/7/20/Picture_7_original.png?1248063204" alt=""  loading="lazy" /></p>
<ul>
<li>
<p>Speaking of &ldquo;Preview,&rdquo; learn to use &ldquo;Quick Look.&rdquo; To view images, videos, audio, PDFs, Office files, iWork files, and so on, just select the file (or a set of files) and press &ldquo;Space.&rdquo; A floating window opens where you can quickly view the file. &ldquo;Space&rdquo; again closes it. You can preview most major file formats without opening their respective programs.</p>
</li>
<li>
<p>On PCs we tend to create custom folders for videos, photos, and the like. On the Mac, try to use the default folders it already gives you. More than that, get in the habit of using iTunes to organize your music and videos, iPhoto for your photos, and iMovie to edit your videos. That keeps your Mac tidy, makes backups easier, simplifies searches, and keeps everything more accessible. Many Apple applications integrate with the iLife suite (iTunes, iPhoto, GarageBand, iMovie, iWeb), so it&rsquo;s simpler to let these apps manage your files. Watch the screencasts on Apple&rsquo;s website if you don&rsquo;t know how they work yet; they&rsquo;re simple, intuitive, and powerful.</p>
</li>
</ul>
<p><img src="http://s3.amazonaws.com/akitaonrails/assets/2009/7/20/Picture_8_original.png" alt=""  loading="lazy" /></p>
<ul>
<li>Installing applications on a Mac usually trips people up at first. You normally download one of two formats: DMG or MPKG. The first stands for (D)isk i(M)a(G)e and is similar to an ISO. When you double-click it, the DMG &ldquo;mounts&rdquo; inside /Volumes. The application is usually already there, and you just drag it to the &ldquo;Applications&rdquo; folder on your Mac. Then you &ldquo;eject&rdquo; the DMG with the ⏏ icon or with ⌘+E. The second format, (M)ac (P)ac(K)a(G)e, is the equivalent of Windows&rsquo; MSI: you double-click it and it runs like a standard installer. Usually only programs that need to install a lot of system components use MPKG, like Microsoft Office and Adobe CS4. Sometimes you download a ZIP that contains a DMG or an MPKG. The important part: if it&rsquo;s a DMG with no MPKG inside, always drag the application to Applications before running it. Safari does an extra step: it downloads the DMG, mounts it, extracts the application, and deletes the DMG, so you drag it from the Downloads folder. A technical detail: MPKGs come with a BOM (Bill of Materials) that works as a recipe of the original system file permissions for scripts that adjust permissions. The same BOM helps uninstall, since it records everything that was installed.</li>
</ul>
<p><img src="http://s3.amazonaws.com/akitaonrails/assets/2009/7/20/Picture_1_original.png" alt=""  loading="lazy" /></p>
<p><img src="http://s3.amazonaws.com/akitaonrails/assets/2009/7/20/Picture_15_original.png" alt=""  loading="lazy" /></p>
<ul>
<li>
<p>All application preferences are stored in your directory (/Users/your_login), then Library/Preferences. They&rsquo;re files in plist format, which is XML stored in binary. Regardless of where the application is copied, it saves preferences in that location. Don&rsquo;t confuse the &ldquo;Library&rdquo; local to your home folder with the global &ldquo;Library&rdquo; at the root of the system, since you&rsquo;ll rarely need to touch the latter. On the Mac there&rsquo;s no Registry, and so no nightmare of maintaining one. When an application starts behaving strangely, the first thing to try is deleting its .plist file.</p>
</li>
<li>
<p>On the Mac, Finder doesn&rsquo;t show every directory. Most are hidden, like /usr, /bin, /tmp, /dev, /var, /etc, and others that Unix or Linux users will recognize. Some important ones like System and Library at the root of your Mac are rarely accessed. User accounts live in the Users folder and applications in the Applications folder. Inside your &ldquo;Home&rdquo; folder are folders like Desktop, Documents, Downloads, Music, Movies, Pictures, Sites, Public, and Library. In that Library are things like &ldquo;Application Support,&rdquo; where plugins and other application dependencies live, and &ldquo;Preferences,&rdquo; which I explained earlier. Poke around these folders; the naming is fairly obvious.</p>
</li>
<li>
<p>Inside the &ldquo;Applications&rdquo; folder there&rsquo;s another called &ldquo;Utilities&rdquo; (also accessible via ⌘+Shift+U) with things like &ldquo;Activity Monitor,&rdquo; similar to the Windows Task Manager. There&rsquo;s also &ldquo;Console,&rdquo; an easy way to review system log files. Another important one is &ldquo;Disk Utility,&rdquo; which does advanced things like repartitioning your disk non-destructively, creating DMG files including encrypted volumes, burning DMGs to DVDs, and more.</p>
</li>
</ul>
<p><img src="http://s3.amazonaws.com/akitaonrails/assets/2009/7/20/Picture_9_original.png" alt=""  loading="lazy" /></p>
<ul>
<li>
<p>Another difference from Windows: Macs don&rsquo;t have drive letters (C:, D:, E:, and so on). The Mac, being a BSD Unix, behaves more like Unix/Linux, where DMG and ISO files are &ldquo;mounted&rdquo; inside the /Volumes directory and show up normally as disks in Finder that can be ejected. The Mac is very flexible with disk images: you can use Disk Utility to create bootable USB drives, create multiple boot partitions, copy DVDs into DMGs, and such. Network shared folders are also mounted in /Volumes. The behavior is consistent and fast, and Finder, unlike Windows Explorer, rarely crashes and almost never returns to an inconsistent state.</p>
</li>
<li>
<p>A technical detail you&rsquo;ll notice: Finder (including the top menu and Desktop), the Dock, and applications are very independent. On Windows, especially XP, you&rsquo;ll remember an application sometimes getting sluggish, hard even to drag, making it difficult to click the Start menu or taskbar. On the Mac, even when Finder crashes or gets slow, the Dock behaves independently. Other applications aren&rsquo;t affected either, including their window refresh. Another tip: if an application truly freezes, use ⌘+⌥+⎋ (Command+Option+Esc) to open a window where you can force-quit it. And ⌘+Shift+Q forces the current user to log out.</p>
</li>
<li>
<p>Speaking of deleting: select files and use ⌘+Shift+⌫. That ⌫ key is called &ldquo;Delete&rdquo; but it&rsquo;s the Mac equivalent of the PC&rsquo;s &ldquo;Backspace.&rdquo; The Mac equivalent of the PC&rsquo;s &ldquo;Delete&rdquo; key is Shift+⌫. You can also do more, like ⌥+⌫ to delete the whole word to the left of your cursor, or ⌘+⌫ to delete to the beginning of the line.</p>
</li>
<li>
<p>For navigating text, get used to combinations like ⌘+← and ⌘+→ to go to the beginning or end of the line, ⌘+↑ or ⌘+↓ for the equivalents of Page Up and Page Down, and ⌥+← and ⌥+→ to move by word left or right. These keys become second nature because you use them constantly.</p>
</li>
<li>
<p>If you&rsquo;re in a text editor (Mail.app, Safari, TextEdit, and so on) and the text is too small to read comfortably, use ⌘-Shift-&rsquo;+&rsquo; to increase the font size and ⌘-Shift-&rsquo;-&rsquo; to decrease it. To zoom in on an image or small detail, hold Ctrl and drag two fingers up on the trackpad to zoom in, or two fingers down to zoom out.</p>
</li>
<li>
<p>Still on text: if you select a passage in any application, you can drag it to the desktop or another folder in Finder. It&rsquo;s saved as a &ldquo;snippet,&rdquo; like a persistent clipboard item you can drag back into another text editor or leave on the desktop until you decide what to do with it.</p>
</li>
<li>
<p>All MacBooks, including older ones, have always had a two-finger multi-touch action for scrolling. Just slide two fingers, without clicking, up or down on the trackpad to scroll, for example in Safari.</p>
</li>
<li>
<p>Before Lion, there was a feature to encrypt your files in real time. It was called FileVault and was bad enough to ignore. But from Lion onward, <strong>FileVault 2</strong> arrived, completely different and this time so good it would be foolish not to use it. Open &ldquo;System Preferences, Security &amp; Privacy,&rdquo; the &ldquo;FileVault&rdquo; tab, and enable full disk encryption. <strong>VERY IMPORTANT:</strong> it generates secure keys that allow decryption of your data. Write them down somewhere safe and <strong>never lose them</strong>. One tip: grab your iPhone or any smartphone with a camera and take a photo of the screen when it shows you the keys.</p>
</li>
</ul>
<p><img src="http://s3.amazonaws.com/akitaonrails/assets/2012/4/20/Screen%20Shot%202012-04-20%20at%206.29.06%20PM_original.png?1334957491" alt=""  loading="lazy" /></p>
<ul>
<li>From Lion onward there&rsquo;s <a href="http://web.archive.org/web/20120522082049/http://www.apple.com/br/macosx/whats-new/mission-control.html"target="_blank" rel="noopener">Mission Control</a>, which you activate by placing four fingers on the trackpad and swiping up. It&rsquo;s a replacement for the old Exposé and genuinely handy once you get used to it. When &ldquo;maximized,&rdquo; applications become their own parallel &ldquo;Space,&rdquo; and you navigate between them by swiping 3 fingers left or right. The default, though, has these Spaces rearranging automatically based on usage. I don&rsquo;t like that, because I prefer my applications and desktops always in the same position (in Mission Control you can drag Spaces to wherever you like). To disable the forced rearrangement, go to &ldquo;System Preferences, Mission Control&rdquo; and turn off &ldquo;Automatically rearrange spaces based on most recent use.&rdquo;</li>
</ul>
<p><img src="http://s3.amazonaws.com/akitaonrails/assets/2012/4/20/Screen%20Shot%202012-04-20%20at%205.57.35%20PM_original.png?1334955644" alt=""  loading="lazy" /></p>
<ul>
<li>Also from Lion onward, the way you save files changed a lot. There&rsquo;s now an &ldquo;Auto Save&rdquo; feature. So if an unexpected crash happens, or you have to force-shutdown the machine, or any drastic situation where you&rsquo;d lose what you were editing, don&rsquo;t worry, because Lion is saving automatically. There is one annoyance, though: the file sometimes gets a &ldquo;Lock&rdquo; that prevents you from editing it. You can unlock it manually, but it&rsquo;s a hassle. I prefer to turn it off by going to &ldquo;System Preferences, Time Machine,&rdquo; clicking the &ldquo;options&rdquo; button, and disabling &ldquo;Lock documents.&rdquo; While you&rsquo;re there, check the photo below for how to do that, and also what I keep on my Time Machine exclusion list, things I&rsquo;d rather not back up either because they don&rsquo;t matter (Software Images, for example) or because I prefer to back them up manually (iPhoto).</li>
</ul>
<p><img src="http://s3.amazonaws.com/akitaonrails/assets/2012/4/20/Screen%20Shot%202012-04-20%20at%206.38.10%20PM_original.png?1334958088" alt=""  loading="lazy" /></p>
<ul>
<li>
<p>Still on the new Lion way of handling documents and versions: in new applications you now have a &ldquo;Save a version&rdquo; option in the menu, so you can save moments in time in case you need to go back and recover an earlier state. Think of it as a mini Time Machine or granular backup. One option that no longer exists is &ldquo;Save As,&rdquo; which let you save the same file under a different name. Instead the operation is a bit more annoying: first &ldquo;Duplicate&rdquo; (all in the same main &ldquo;File&rdquo; menu) and then &ldquo;Save&rdquo; to store it under a different name. Get used to it; it&rsquo;s annoying at first but becomes trivial.</p>
</li>
<li>
<p>The Mac has plenty of unexpected surprises. In the main menu, the item with the application&rsquo;s name always has a sub-item called &ldquo;Services.&rdquo; Try selecting a block of text in any application, then go to the &ldquo;Services&rdquo; menu, then &ldquo;Speech,&rdquo; then &ldquo;Start Speaking Text,&rdquo; and the Mac reads the selected text aloud. Unfortunately there&rsquo;s no option in Portuguese.</p>
</li>
</ul>
<p><img src="http://s3.amazonaws.com/akitaonrails/assets/2009/7/20/Picture_11_original.png" alt=""  loading="lazy" /></p>
<ul>
<li>
<p>In Finder you have the &ldquo;Go&rdquo; menu, then &ldquo;Connect to Server,&rdquo; or the shortcut ⌘+K, to connect to shared folders on other Macs or on your company&rsquo;s Windows file server. For a Windows server you&rsquo;re used to typing something like \server\folder. On the Mac you type something like smb://server.domain/folder. If your server is Windows 2000 or later, include the full server name, including the root domain of your directory. Usually that&rsquo;s all you need.</p>
</li>
<li>
<p>There&rsquo;s no shortcut to force-lock your computer so nobody can access it while you&rsquo;re away. One way is the screen saver. First, open &ldquo;System Preferences&rdquo; and &ldquo;Security&rdquo; and enable &ldquo;Require password to wake this computer from sleep or screen saver.&rdquo; Now, still in &ldquo;System Preferences,&rdquo; choose &ldquo;Desktop &amp; Screen Saver,&rdquo; then &ldquo;Screen Saver.&rdquo; On that screen there&rsquo;s a &ldquo;Hot Corners&rdquo; option where you can pick a corner that starts the screensaver when you move the mouse there. That gives you a quick way to lock your computer.</p>
</li>
<li>
<p>Every time you download a program from the internet, the first time you run it the Mac shows you the URL it was downloaded from and asks for confirmation. To be prompted whenever you or something tries to modify a system setting, go to &ldquo;System Preferences,&rdquo; &ldquo;Security,&rdquo; and enable &ldquo;Require password to unlock each System Preferences pane.&rdquo; The Mac warns you whenever something tries to escalate authority, and you enter your administrator password to confirm. For Linux users, it&rsquo;s like using &ldquo;sudo&rdquo; in the Terminal. The Mac is quite secure: its architecture keeps trivial malware from taking over the machine the way it does on Windows, and that has nothing to do with market share, since the user has to explicitly do something foolish to get compromised. Antivirus is only useful to make sure you don&rsquo;t forward someone an infected attachment you received. Your machine stays fine, but you might pass the virus along by accident.</p>
</li>
<li>
<p>You&rsquo;ll miss programs like Norton Utilities because you simply don&rsquo;t need them. For a defragmenter, for example, Mac OS defragments automatically for you. Also understand that your filesystem is HFS+, not FAT or NTFS. One quirk is that HFS+ has <a href="http://en.wikipedia.org/wiki/Resource_fork"target="_blank" rel="noopener">Resource Forks</a>, so when you copy Mac files to FAT USB drives you end up with what look like &ldquo;duplicate&rdquo; files with an underscore at the start of the name, which is the resource fork representation on filesystems that don&rsquo;t support it. Also understand that every Mac &ldquo;application&rdquo; is actually a folder with a &ldquo;.app&rdquo; extension and an icon. When transporting applications, don&rsquo;t copy them straight to a FAT USB drive; first put them in a DMG or just zip them (the &ldquo;Archive&rdquo; option in the context menu), then copy. Remember too that Unix files have permissions and FAT doesn&rsquo;t preserve them.</p>
</li>
<li>
<p>The equivalent of Windows Startup Items is in &ldquo;System Preferences,&rdquo; &ldquo;Accounts,&rdquo; your user, &ldquo;Login Items.&rdquo;</p>
</li>
<li>
<p>The Mac is a BSD Unix. As such, it has a Terminal application in the Utilities folder. Use Spotlight to reach it easily. It opens a BASH shell, and from there you can manipulate files and programs easily in a POSIX environment. If you come from Linux, you&rsquo;ll feel right at home.</p>
</li>
<li>
<p>Speaking of Linux, one weak spot is the lack of a good package manager. On Ubuntu/Debian we have apt-get; on Redhat/Fedora/CentOS we have Yum. On the Mac there&rsquo;s no standard. My recommendation is <a href="http://web.archive.org/web/20120419165352/http://mxcl.github.com/homebrew/"target="_blank" rel="noopener">HomeBrew</a>, a system for installing and maintaining open source projects. It&rsquo;s not as powerful or robust as Aptitude on Ubuntu, but it does its job well. You&rsquo;ll also come across others like MacPorts and Fink, but they&rsquo;re either outdated or more hassle, so I don&rsquo;t recommend them. See the next tip.</p>
</li>
<li>
<p><a href="https://github.com/mxcl/homebrew"target="_blank" rel="noopener">HomeBrew</a> is the best installer for open-source software like MySQL, PostgreSQL, Redis, Git, Android SDK, and much more. In some cases it downloads the Mac binary directly, but usually it downloads the source code, applies necessary patches, and compiles. For that you need compilers and other tools. The simplest way is to use the <strong>App Store</strong> to buy and download XCode. This tip is more for software developers; if you&rsquo;re not one, you can ignore it.</p>
</li>
<li>
<p>Every Mac comes with Apache 2 pre-installed. It&rsquo;s hidden under the name &ldquo;Web Sharing.&rdquo; You&rsquo;ll find it in System Preferences, &ldquo;Sharing,&rdquo; then &ldquo;Web Sharing.&rdquo; When you turn this on or off, you&rsquo;re dealing with Apache 2, which by default looks at the &ldquo;Sites&rdquo; folder in your Users/Home directory. Another option, &ldquo;Remote Login,&rdquo; enables or disables OpenSSH access. &ldquo;Screen Sharing,&rdquo; in turn, activates a VNC server, so a VNC client on Windows can also share the screen of your Mac.</p>
</li>
</ul>
<p><img src="http://s3.amazonaws.com/akitaonrails/assets/2009/7/20/Picture_10_original.png" alt=""  loading="lazy" /></p>
<ul>
<li>
<p>One weakness fixed from Snow Leopard onward is the Firewall. On Leopard and earlier it ships disabled. Open System Preferences again, option &ldquo;Security,&rdquo; then &ldquo;Firewall.&rdquo; It comes set to &ldquo;Allow all incoming connections.&rdquo; Change it at minimum to &ldquo;Allow only essential services&rdquo; or, better, &ldquo;Set access for specific services and applications,&rdquo; which works as a whitelist. Everything is blocked by default, and only the applications you select in the box below get open ports.</p>
</li>
<li>
<p>Lion is the most practical version for disaster recovery. There&rsquo;s no more boot DVD. Every Mac now has a hidden partition with the installer, for when you need to reinstall, check disks, or do other things. Just boot while holding (Command-R) ⌘-R, or hold the (Option) ⌥ key during boot to get a menu with the available partitions and choose &ldquo;Recovery HD.&rdquo;</p>
</li>
</ul>
<p><a href="http://www.apple.com/macosx/recovery/"target="_blank" rel="noopener"><img src="http://s3.amazonaws.com/akitaonrails/assets/2012/4/20/commandr_original.jpg?1334958455" alt=""  loading="lazy" /></a></p>
<ul>
<li>Finally, to impress your friends: when you minimize a window, use Exposé, or activate the Dashboard, all these actions have animated transitions. Hold the &ldquo;Shift&rdquo; key at the same time and the animation plays in <em>slow motion</em>, showing every step of the transition at slow speed :-)</li>
</ul>
<p><img src="http://s3.amazonaws.com/akitaonrails/assets/2009/7/21/Picture_18_original.png" alt=""  loading="lazy" /></p>
<h3>Applications<span class="hx:absolute hx:-mt-20" id="applications"></span>
    <a href="#applications" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Some of the applications below are on the Mac App Store, and I always recommend checking there first. Otherwise, follow the links and download manually. At the end of this section I have a tip on keeping your applications up to date.</p>
<ul>
<li>
<p>If you have an iPad, you can use it as a second monitor connected to your Mac over Wi-Fi (both need to be on the same network). For this, buy <a href="http://web.archive.org/web/20120420081551/http://avatron.com/apps/air-display"target="_blank" rel="noopener">Air Display</a>.</p>
</li>
<li>
<p>If you have a new Apple TV (the small black model), you can mirror the screen of your iPhone 4S, iPad 2, or later over Wi-Fi using the <a href="http://support.apple.com/kb/HT4437?viewlocale=pt_PT&amp;locale=pt_PT"target="_blank" rel="noopener">Air Play</a> feature on iOS. The next version of Mac, Mountain Lion, will let you do the same from your Mac. Until then, you can still mirror your Mac to an HDTV via Apple TV by buying <a href="http://airparrot.com/"target="_blank" rel="noopener">Air Parrot</a>. It&rsquo;s the simplest way to watch movies and videos from your Mac straight on your TV.</p>
</li>
<li>
<p>I personally love reading a lot of RSS and Atom feeds in my Google Reader account, and the best Mac and iOS app for that is easily <a href="http://reederapp.com/mac/"target="_blank" rel="noopener">Reeder</a>.</p>
</li>
<li>
<p>With so much internet content, you download a lot but don&rsquo;t always know which files are eating the most disk space. To find them (tip: most of the time it&rsquo;s your video podcasts in iTunes) there are excellent paid apps like <a href="http://www.daisydiskapp.com/"target="_blank" rel="noopener">DaisyDisk</a>, but I still like the free <a href="http://grandperspectiv.sourceforge.net/"target="_blank" rel="noopener">GrandPerspective</a>.</p>
</li>
<li>
<p>OS X handles compressed formats like zip and gz on its own. But to decompress more interesting formats like 7-zip and rar, be sure to install <a href="http://wakaba.c3.cx/s/apps/unarchiver.html"target="_blank" rel="noopener">The Unarchiver</a>.</p>
</li>
<li>
<p>For applications, use sites like Apple&rsquo;s own to see what&rsquo;s <a href="http://www.apple.com/downloads/macosx/index_top.html"target="_blank" rel="noopener">most popular</a>. To start, you&rsquo;ll want <a href="http://perian.org"target="_blank" rel="noopener">Perian</a> for more video codecs, <a href="http://www.telestream.net/flip4mac-wmv/overview.htm"target="_blank" rel="noopener">Flip4Mac</a> for Windows codecs, and <a href="http://www.videolan.org/vlc/download-macosx.html"target="_blank" rel="noopener">VLC</a> for a player that handles all the strangest codecs.</p>
</li>
<li>
<p>To rip DVDs and create mp4 files, use the freeware <a href="http://handbrake.fr/"target="_blank" rel="noopener">HandBrake</a>. To convert videos for iPod and iPhone, use <a href="http://www.macupdate.com/info.php/id/19769"target="_blank" rel="noopener">iSquint</a>. To create, edit, and convert subtitle files, use <a href="http://www.fluffalopefactory.com/miyu/"target="_blank" rel="noopener">Miyu</a> and <a href="http://www.bitfield.se/submerge/index.html"target="_blank" rel="noopener">Submerge</a>.</p>
</li>
<li>
<p>For presentations, forget Powerpoint. It&rsquo;s very <strong>worth</strong> buying <a href="http://web.archive.org/web/20110107211503/http://www.apple.com/iwork/download-trial/"target="_blank" rel="noopener">iWork</a> to use the famous Keynote. The iLife and iWork suites are all on the App Store, so buy them there.</p>
</li>
</ul>
<p><img src="http://s3.amazonaws.com/akitaonrails/assets/2009/7/20/whatsnew-hero-20090106_original.jpg" alt=""  loading="lazy" /></p>
<ul>
<li>
<p>For communication, use <a href="http://adium.im/"target="_blank" rel="noopener">Adium</a>, a client for Jabber, Messenger, Yahoo, AIM, and more, one of the best around, though it doesn&rsquo;t yet support video chat for Messenger. The classic <a href="http://www.skype.com/intl/pt/download/skype/macosx/"target="_blank" rel="noopener">Skype</a> is another great option. If you like IRC, one of the best clients is <a href="http://web.archive.org/web/20090717071516/http://colloquy.info/"target="_blank" rel="noopener">Colloquy</a>.</p>
</li>
<li>
<p>You want to run Windows or some Linux distro. The option that comes with the Mac is Bootcamp (in Utilities), to repartition your HD and install a second operating system. Before that, though, I recommend virtualization products like the open-source <a href="http://www.virtualbox.org/wiki/Downloads"target="_blank" rel="noopener">VirtualBox</a>, or the commercial <a href="http://www.parallels.com/download/desktop/"target="_blank" rel="noopener">Parallels Desktop</a> or <a href="http://web.archive.org/web/20090719015503/http://www.vmware.com/products/fusion/"target="_blank" rel="noopener">VMWare Fusion</a>. They&rsquo;re all very good. With them you can run Windows XP or Windows 7 (I don&rsquo;t recommend Vista unless you have a desktop Mac with more than 4GB of RAM), Ubuntu, Fedora, and so on. In most cases, even heavy stuff like SQL Server with Visual Studio works great. For games, no, better to dual-boot, or better yet, buy a PlayStation 3 or Xbox 360.</p>
</li>
<li>
<p>The Mac is quite secure. Things like saving passwords in Safari go into an infrastructure called Keychain, an encrypted, secure storage. You can even encrypt your entire Home folder if you want. For other things, like sharing authentication data across multiple browsers or just storing notes securely, I suggest <a href="http://agilewebsolutions.com/products/1Password"target="_blank" rel="noopener">1Password</a>, one of the best out there.</p>
</li>
<li>
<p>Macs normally don&rsquo;t need uninstallers. For the vast majority of programs you just drag them to the Applications folder, so you delete them from there. They do leave behind a few artifacts, like files in the Library/Preferences directory. Normally it&rsquo;s fine to leave them; they&rsquo;re tiny and don&rsquo;t corrupt anything like a Registry. But if you&rsquo;re the paranoid type who needs to remove everything, use <a href="http://www.appzapper.com/"target="_blank" rel="noopener">AppZapper</a>, which does it for you.</p>
</li>
<li>
<p>Anyone who&rsquo;s watched Mac screencasts online might wonder, <em>&ldquo;How do they do that?&rdquo;</em> One of the secrets is the commercial <a href="http://www.telestream.net/screen-flow/overview.htm"target="_blank" rel="noopener">ScreenFlow</a>, by far one of the best, most performant, and easiest to use. Worth every cent. To record the keyboard shortcuts you&rsquo;re using as a layer on top of your video, use <a href="http://web.archive.org/web/20090801050033/http://stephendeken.net/software/keycastr/"target="_blank" rel="noopener">KeyCastr</a>. For mouse effects like focus and others, use <a href="http://web.archive.org/web/20090802092433/http://www.omnigroup.com/applications/omnidazzle/download/"target="_blank" rel="noopener">OmniDazzle</a>.</p>
</li>
</ul>
<p><a href="http://peepcode.com/products/screencasting-on-the-mac"target="_blank" rel="noopener"><img src="http://s3.amazonaws.com/akitaonrails/assets/2009/7/20/screencasting-on-the-mac_original.png" alt=""  loading="lazy" /></a></p>
<ul>
<li>
<p>The Mac needs very little maintenance, and most tools are already built into the operating system. As a visual shell to reach them more easily, use <a href="http://web.archive.org/web/20090802092434/http://www.titanium.free.fr/pgs2/english/download.html"target="_blank" rel="noopener">Onyx</a>, which runs all the maintenance scripts at once. Sometimes, when your Mac starts behaving strangely, running Onyx helps a lot, though that situation is very rare.</p>
</li>
<li>
<p>As a text editor there&rsquo;s no getting around it: after 3 years my favorite is still TextMate. If you&rsquo;re more of a Linux purist, you might prefer <a href="http://code.google.com/p/macvim/"target="_blank" rel="noopener">MacVim</a>, especially with my <a href="http://web.archive.org/web/20090725080422/http://akitaonrails.com/2009/04/27/the-best-environment-for-rails-on-windows-part-2"target="_blank" rel="noopener">Ruby snippets package</a> :-) Beyond those, there are dozens of other editors, but none really appealed to me. A plugin that makes TextMate even nicer is <a href="http://code.google.com/p/textmate-missingdrawer/"target="_blank" rel="noopener">MissingDrawer</a>, which I recommend trying. If you&rsquo;re a developer, follow my <a href="http://web.archive.org/web/20091005093524/http://github.com/akitaonrails/vimfiles"target="_blank" rel="noopener">vimfiles</a> repository to get your Vim pre-configured with the best of what&rsquo;s available.</p>
</li>
<li>
<p>For downloaders, Mozilla Firefox has various extensions, or if you&rsquo;re a solid Linux user you&rsquo;ll know how to use good old curl. But if you want something more visual, an excellent commercial alternative is <a href="http://yazsoft.com/"target="_blank" rel="noopener">Speed Download</a>, which has options for parallel downloads, resuming interrupted downloads, and so on. Still on downloads, if you&rsquo;re into BitTorrent, one of the best clients is <a href="http://web.archive.org/web/20090719033742/http://www.transmissionbt.com/download.php"target="_blank" rel="noopener">Transmission</a>.</p>
</li>
<li>
<p>For burning DVDs, the Mac handles it reasonably well on its own. But if you want more control and detail, one of the most traditional and best commercial options is <a href="http://www.roxio.com/enu/products/toast/default.html"target="_blank" rel="noopener">Toast</a> by Roxio, the equivalent of Nero on Windows. For something simpler there&rsquo;s <a href="http://web.archive.org/web/20090721195744/http://www.discoapp.com/"target="_blank" rel="noopener">Disco</a>, one of the most visually beautiful, with a feature that keeps a database of DVDs you&rsquo;ve burned to make searches easier. And a decent freeware is <a href="http://burn-osx.sourceforge.net/Pages/English/home.html"target="_blank" rel="noopener">Burn</a>.</p>
</li>
<li>
<p>Even though Time Machine already does an excellent job of backup, <a href="http://www.shirt-pocket.com/SuperDuper/SuperDuperDescription.html"target="_blank" rel="noopener">SuperDuper!</a> remains an excellent alternative. It makes a bit-for-bit image of your system, supports delta updates, and lets you create bootable external hard drives. It&rsquo;s a good thing to do before anything drastic, like installing a new version of Mac OS. It&rsquo;s the equivalent of Norton Ghost on Windows.</p>
</li>
<li>
<p>If you&rsquo;re a developer using Git with Gitk, you can install Git via <a href="http://web.archive.org/web/20120419165352/http://mxcl.github.com/homebrew/"target="_blank" rel="noopener">HomeBrew</a> (with HomeBrew installed, just open a Terminal and use &ldquo;brew install git&rdquo;) and then use <a href="http://gitx.frim.nl/"target="_blank" rel="noopener">Gitx</a> instead of the ugly Gitk. It uses Cocoa components, so it has the look and feel of a native Mac app.</p>
</li>
<li>
<p>If you have an iPod, know that it can play Audiobooks. Unlike mp3 and aac, the standard audiobook format is m4b, or mpeg-4 with bookmark support. That&rsquo;s very important because mp3 has no bookmarks, and when a book is 20 hours long it&rsquo;s painful if your iPod loses your place, or worse, if you want to navigate between chapters of a 40-hour book. If you have audiobooks in mp3, use <a href="http://www.splasm.com/audiobookbuilder/"target="_blank" rel="noopener">Audiobook Builder</a>, which compiles all the mp3s into a single m4b that your iTunes syncs to your iPod.</p>
</li>
<li>
<p>You were a Windows developer with dozens of e-books in Microsoft&rsquo;s CHM (compiled HTML) format. Fortunately, on the Mac you have the open-source reader <a href="http://chmox.sourceforge.net/"target="_blank" rel="noopener">Chmox</a>.</p>
</li>
<li>
<p>Say you have two computers, or some external hard drives, and you need to keep some folders in sync. Again, if you&rsquo;re a solid Linux user, you can comfortably use &ldquo;rsync&rdquo; from the command line. But if you want a visual shell for rsync, a great option is <a href="http://www.econtechnologies.com/pages/cs/chrono_overview.html"target="_blank" rel="noopener">ChronoSync</a>, which allows bi-directional synchronization and much more. It&rsquo;s how I keep two 500GB external hard drives synced through my Mac Mini, a poor man&rsquo;s RAID 1 :-)</p>
</li>
<li>
<p>A well-known subsystem is <a href="http://web.archive.org/web/20090722012006/http://www.growl.info/"target="_blank" rel="noopener">Growl</a>, a notification infrastructure. For example, when an application like Transmission finishes a download, it sends a message to Growl, which pops up on your desktop to notify you. Adium also uses it to show who came online, and so on. Growl ships with plugins for iTunes and Mail.app, plus a command-line tool to integrate with other applications.</p>
</li>
<li>
<p>Mail.app is organized with a list of emails on top and a view of the selected email below. Some prefer vertical bars instead of horizontal, more like Outlook. In that case use the <a href="http://web.archive.org/web/20090802092437/http://harnly.net/software/letterbox/"target="_blank" rel="noopener">LetterBox</a> plugin for Mail.app.</p>
</li>
<li>
<p>A famous but more advanced application is the legendary <a href="http://quicksilver.en.softonic.com/"target="_blank" rel="noopener">QuickSilver</a>, which some see only as a fast way to find applications, but which is really a sophisticated environment for chaining functionality. You can, for example, find and select several files, attach them to an email, and send it to an address in your Address Book. It has dozens of plugins and themes for customization. It&rsquo;s interesting at first, and there are various clones with the same idea, but in the end you&rsquo;ll notice you mostly use it just to find applications. And for that, the simplest thing is Command ⌘ + Space to activate Spotlight (the magnifying glass in the upper-right corner) and type the application&rsquo;s name. Same for finding documents. I find it more practical and faster.</p>
</li>
</ul>
<p><img src="http://s3.amazonaws.com/akitaonrails/assets/2009/7/20/Picture_12_original.png" alt=""  loading="lazy" /></p>
<ul>
<li>
<p>Those coming from Windows might still need to reach their old machine, or at the office deal with Windows programs. Fortunately, Windows has RDP (Remote Desktop Protocol) for remote access. On the Mac the best option is <a href="http://cord.sourceforge.net/"target="_blank" rel="noopener">CoRD</a>, the equivalent of a Terminal Client.</p>
</li>
<li>
<p>A very useful utility for monitoring your CPU, RAM, disk, and network usage is <a href="http://www.apple.com/downloads/dashboard/status/istatpro.html"target="_blank" rel="noopener">iStat Pro</a>, which has a widget version for the Dashboard, or <a href="http://web.archive.org/web/20090717080452/http://www.islayer.com/apps/istatmenus/"target="_blank" rel="noopener">iStat Menu</a> for the top menu bar. I personally prefer the second, but both are very good.</p>
</li>
<li>
<p>A well-known benchmarker in the Mac world is <a href="http://www.xbench.com/"target="_blank" rel="noopener">XBench</a>, which tests your Mac and lets you compare results on their website against other Macs.</p>
</li>
<li>
<p>The last tip is to create an account on <a href="http://www.macupdate.com/"target="_blank" rel="noopener">MacUpdate</a> and then download the <a href="http://www.macupdate.com/desktop/"target="_blank" rel="noopener">MacUpdate Desktop</a> software. Open it occasionally and it tells you everything that&rsquo;s outdated on your machine, letting you pick what to update:</p>
</li>
</ul>
<p><img src="http://s3.amazonaws.com/akitaonrails/assets/2012/4/20/Screen%20Shot%202012-04-20%20at%206.14.40%20PM_original.png?1334956624" alt=""  loading="lazy" /></p>
<h3>History<span class="hx:absolute hx:-mt-20" id="history"></span>
    <a href="#history" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>To understand Mac OS X, you need to understand its history. For that, the best set of articles are the ones ArsTechnica has written since 2000:</p>
<ul>
<li>
<p><a href="http://arstechnica.com/reviews/4q99/macos-x-dp2/macos-x-dp2-1.html"target="_blank" rel="noopener">Mac OS X DP2: A Preview</a></p>
</li>
<li>
<p><a href="http://arstechnica.com/reviews/1q00/macos-x-gui/macos-x-gui-1.html"target="_blank" rel="noopener">Mac OS X Update: Quartz &amp; Aqua</a></p>
</li>
<li>
<p><a href="http://arstechnica.com/reviews/1q00/macos-x-dp3/macos-x-dp3-1.html"target="_blank" rel="noopener">Mac OS X DP3: Trial by Water</a></p>
</li>
<li>
<p><a href="http://www.arstechnica.com/reviews/2q00/macos-x-dp4/macos-x-dp4-1.html"target="_blank" rel="noopener">Mac OS X DP4</a></p>
</li>
<li>
<p><a href="http://www.arstechnica.com/reviews/2q00/macos-qna/macos-x-qa-1.html"target="_blank" rel="noopener">Mac OS X Q &amp; A</a></p>
</li>
<li>
<p><a href="http://arstechnica.com/reviews/4q00/macosx-pb1/macos-x-beta-1.html"target="_blank" rel="noopener">Mac OS X Public Beta</a></p>
</li>
<li>
<p><a href="http://arstechnica.com/reviews/01q1/macwldsf/mwsf-2.html"target="_blank" rel="noopener">MWSF: Mac OS X Post-Beta</a></p>
</li>
<li>
<p><a href="http://arstechnica.com/reviews/01q2/macos-x-final/macos-x-1.html"target="_blank" rel="noopener">Mac OS X 10.0 Cheetah</a></p>
</li>
<li>
<p><a href="http://arstechnica.com/apple/reviews/2001/10/macosx-10-1.ars"target="_blank" rel="noopener">Mac OS X 10.1 Puma</a></p>
</li>
<li>
<p><a href="http://arstechnica.com/apple/reviews/2002/09/macosx-10-2.ars"target="_blank" rel="noopener">Mac OS X 10.2 Jaguar</a></p>
</li>
<li>
<p><a href="http://arstechnica.com/apple/reviews/2003/11/macosx-10-3.ars"target="_blank" rel="noopener">Mac OS X 10.3 Panther</a></p>
</li>
<li>
<p><a href="http://arstechnica.com/apple/reviews/2005/04/macosx-10-4.ars"target="_blank" rel="noopener">Mac OS X 10.4 Tiger</a></p>
</li>
<li>
<p><a href="http://arstechnica.com/apple/reviews/2007/10/mac-os-x-10-5.ars"target="_blank" rel="noopener">Mac OS X 10.5 Leopard: the Ars Technica review</a></p>
</li>
<li>
<p><a href="http://arstechnica.com/apple/reviews/2009/08/mac-os-x-10-6.ars"target="_blank" rel="noopener">Mac OS X 10.6 Snow Leopard: the Ars Technica review</a></p>
</li>
<li>
<p><a href="http://arstechnica.com/apple/reviews/2011/07/mac-os-x-10-7.ars"target="_blank" rel="noopener">Mac OS X 10.6 Lion: the Ars Technica review</a></p>
</li>
</ul>
<p>Also understand that Mac OS X is completely different from its predecessor, the Mac OS, which ended its life at version 9. When Steve Jobs was forced out of Apple in 1985, he founded the company Next and built the <a href="http://en.wikipedia.org/wiki/Nextstep"target="_blank" rel="noopener">NextStep</a> operating system, a 32-bit, multitasking OS with a Mach-based kernel. Watch Steve Jobs himself <a href="http://www.youtube.com/watch?v=j02b8Fuz73A"target="_blank" rel="noopener">demonstrating NextStep</a> version 3. NextStep was later opened as a standard together with Sun as <a href="http://en.wikipedia.org/wiki/OpenStep"target="_blank" rel="noopener">OpenStep</a>. The <a href="http://www.windowmaker.info/"target="_blank" rel="noopener">WindowMaker</a> window manager is inspired by OpenStep and supports its open-source implementation, <a href="http://gnustep.org/"target="_blank" rel="noopener">GNUStep</a>. Later, in 1997, Apple reacquired Next, and NextStep became the foundation for Mac OS X. Its development framework was renamed <a href="http://en.wikipedia.org/wiki/Cocoa_%28API%29"target="_blank" rel="noopener">Cocoa</a>, which is why the development APIs have names like NSString and NSWindow, where &ldquo;NS&rdquo; stands for &ldquo;NextStep.&rdquo;</p>
]]></content:encoded><category>apple</category><category>developer-tools</category><category>learning</category><category>off-topic</category></item></channel></rss>