<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[bmax]]></title><description><![CDATA[bmax]]></description><link>https://imbmax.com</link><image><url>https://cdn.hashnode.com/res/hashnode/image/upload/v1725262443215/ed8ded4c-154e-4b33-bf79-27c5c4f439b7.png</url><title>bmax</title><link>https://imbmax.com</link></image><generator>RSS for Node</generator><lastBuildDate>Sat, 18 Apr 2026 14:09:11 GMT</lastBuildDate><atom:link href="https://imbmax.com/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Why I Actually Settled on JetBrains IDEs (After All That Editor Hopping)]]></title><description><![CDATA[Remember my post about switching to VSCode? Well, plot twist: the very next day after publishing it, I switched to WebStorm. And guess what? I've been on JetBrains IDEs ever since.
I know, I know. Another "why I switched editors" post. But hear me ou...]]></description><link>https://imbmax.com/why-i-actually-settled-on-jetbrains-ides-after-all-that-editor-hopping</link><guid isPermaLink="true">https://imbmax.com/why-i-actually-settled-on-jetbrains-ides-after-all-that-editor-hopping</guid><category><![CDATA[Jetbrains]]></category><category><![CDATA[golang]]></category><category><![CDATA[WebStorm]]></category><category><![CDATA[vim]]></category><category><![CDATA[Emacs]]></category><category><![CDATA[neovim]]></category><category><![CDATA[Text Editors]]></category><category><![CDATA[VS Code]]></category><dc:creator><![CDATA[Bhanuka Mallawaarachchi]]></dc:creator><pubDate>Sat, 09 Aug 2025 18:48:06 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1754764428700/59e5d39e-2974-4c3a-9d05-3e5d129a7520.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Remember my post about switching to VSCode? Well, plot twist: the very next day after publishing it, I switched to WebStorm. And guess what? I've been on JetBrains IDEs ever since.</p>
<p>I know, I know. Another "why I switched editors" post. But hear me out—this time it actually stuck, and I think I've finally figured out why.</p>
<h2 id="heading-the-reality-check">The Reality Check</h2>
<p>After years of hopping between Vim, Emacs, and VSCode, I've settled into a workflow that's honestly just... practical. I use GoLand for Go and frontend development, and CLion for exploring raylib and other C/C++ (or Odin with Odin plugin) projects.</p>
<p>The thing is, I had some WebStorm experience before—maybe a month or two here and there between my various editor adventures. But this time, something clicked differently.</p>
<h2 id="heading-what-vscode-got-wrong-for-me">What VSCode Got Wrong (For Me)</h2>
<p>Don't get me wrong, VSCode has incredible out-of-the-box support for most technologies. But its UX just never sat right with me. Take project-wide text search, for example. VSCode crams those results into a tiny sidebar that's genuinely painful to navigate. Compare that to Vim's quickfix list or Emacs' xref results—even these supposedly "rudimentary" editors (spoiler: they're not) handle search results way more elegantly.</p>
<p>Build configuration is another pain point. Maybe I'm missing something, but I've never been able to wrap my head around VSCode's build configuration with those JSON files. In Vim, you set <code>makeprg</code> and you're done. In Emacs, you configure a compile command or use async shell commands. Simple. Intuitive.</p>
<p>That workflow never clicked for me. Zed gets this right—you can run arbitrary commands and bind keys to re-run them. JetBrains takes a similar approach but excels especially when it comes to running tests, debugging, and build configurations—it's all just straightforward and works without fighting the tool.</p>
<h2 id="heading-why-jetbrains-just-works">Why JetBrains Just Works</h2>
<p>Here's the thing about JetBrains IDEs: they actually live up to that "it just works" promise, but in a more real way than VSCode ever did for me.</p>
<p>Setting up builds, running tests, debugging—it's all straightforward. No hunting through documentation to figure out which JSON schema you need. No wondering why your launch configuration isn't working. You just... do the thing you want to do.</p>
<p>Sure, JetBrains IDEs aren't as keyboard-driven as Vim or Emacs out of the box. But here's where it gets interesting: I found some JetBrains plugins that make the editing experience much closer to Emacs. This gave me the best of both worlds—JetBrains' excellent tooling with more familiar keybindings and editing patterns.</p>
<h2 id="heading-the-right-tool-for-the-job">The Right Tool for the Job</h2>
<p>These days, my setup is simple:</p>
<ul>
<li><p><strong>GoLand</strong> for Go + frontend work</p>
</li>
<li><p><strong>CLion</strong> for exploring raylib, etc</p>
</li>
</ul>
<p>Here's something interesting about JetBrains' licensing: you don't actually need WebStorm if you have GoLand. Any upper-tier IDE like GoLand, IntelliJ IDEA Ultimate, or CLion includes all the WebStorm functionality built right in. So even though I do web development at work, GoLand handles JavaScript, TypeScript, React, and all the web technologies just as well as WebStorm would. It's essentially WebStorm plus Go support, not a separate thing entirely.</p>
<p>Also worth noting—JetBrains offers free non-commercial licenses for many of their IDEs like CLion, Rider, and WebStorm, which makes experimenting with different tools much more accessible.</p>
<p>This feels more mature than trying to make one editor do everything, while also being more practical than juggling multiple specialized tools when you don't need to.</p>
<p>I still use Cursor occasionally for AI capabilities, but when I'm actually writing code? JetBrains runs the show.</p>
<h2 id="heading-looking-back-at-the-journey">Looking Back at the Journey</h2>
<p>My editor journey—Vim → Emacs → VSCode → JetBrains—wasn't really about finding the "best" editor. It was about finding what works for me, right now, with the kind of work I'm doing and the setup I have.</p>
<p>Will I switch again in the future? Maybe. But for now, I'm not fighting my tools anymore. I'm just getting work done.</p>
<p>And honestly? That feels pretty good.</p>
<hr />
<p><em>What's your take on the great editor debate? Have you found your "final" editor, or are you still on the journey? Let me know in the comments below.</em></p>
]]></content:encoded></item><item><title><![CDATA[Getting user input in Odin CLI apps]]></title><description><![CDATA[I had been doing some basic interpreter work in Go and wanted to redo it in another language to solidify my understanding. Naturally, I chose Odin, it’s another great language, with a Go-like, easy-to-approach syntax and no unnecessary complexity.
I ...]]></description><link>https://imbmax.com/getting-user-input-in-odin-cli-apps</link><guid isPermaLink="true">https://imbmax.com/getting-user-input-in-odin-cli-apps</guid><category><![CDATA[odin]]></category><category><![CDATA[odinlang]]></category><dc:creator><![CDATA[Bhanuka Mallawaarachchi]]></dc:creator><pubDate>Thu, 22 May 2025 18:03:06 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1747936835864/5e08a487-31f5-46df-81d4-24136108d94c.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I had been doing some basic interpreter work in Go and wanted to redo it in another language to solidify my understanding. Naturally, I chose Odin, it’s another great language, with a Go-like, easy-to-approach syntax and no unnecessary complexity.</p>
<p>I had previously used Odin while building the Jack compiler for my Nand2Tetris projects last year, and I really enjoyed the experience.</p>
<p>As I began reimplementing my interpreter in Odin, I realized I’d never actually dealt with reading interactive user input from the command line. Since I needed a REPL, this was a must. Surprisingly, just like Go’s bufio pattern, it’s not super obvious how to do this in Odin either.</p>
<p>After digging around in the Odin Discord, I found how to do it.</p>
<p>And here is a REPL that echoes your input:</p>
<pre><code class="lang-rust">package main

import <span class="hljs-string">"core:bufio"</span>
import <span class="hljs-string">"core:fmt"</span>
import <span class="hljs-string">"core:os"</span>

main :: proc() {

    scanner: bufio.Scanner
    stdin := os.stream_from_handle(os.stdin)
    bufio.scanner_init(&amp;scanner, stdin, context.temp_allocator)

    <span class="hljs-keyword">for</span> {
        fmt.printf(<span class="hljs-string">"&gt; "</span>)
        <span class="hljs-keyword">if</span> !bufio.scanner_scan(&amp;scanner) {
            <span class="hljs-keyword">break</span>
        }
        line := bufio.scanner_text(&amp;scanner)
        <span class="hljs-keyword">if</span> line == <span class="hljs-string">"q"</span> {<span class="hljs-keyword">break</span>}
        fmt.println(line)
    }

    <span class="hljs-keyword">if</span> err := bufio.scanner_error(&amp;scanner); err != nil {
        fmt.eprintln(<span class="hljs-string">"error scanning input: %v"</span>, err)
    }

    free_all(context.temp_allocator)
}
</code></pre>
]]></content:encoded></item><item><title><![CDATA[How I Wrote My First VSCode Extension to Bring Emacs Keybindings to My Workflow]]></title><description><![CDATA[Why Emacs Keybindings?
I've always preferred Emacs-style editing, especially the way it handles cursor movement and text manipulation. Even though I have switched to using VSCode for most of my development work, I often found myself missing the intui...]]></description><link>https://imbmax.com/how-i-wrote-my-first-vscode-extension-to-bring-emacs-keybindings-to-my-workflow</link><guid isPermaLink="true">https://imbmax.com/how-i-wrote-my-first-vscode-extension-to-bring-emacs-keybindings-to-my-workflow</guid><category><![CDATA[vscode extensions]]></category><category><![CDATA[Emacs]]></category><category><![CDATA[Text Editors]]></category><category><![CDATA[vscode]]></category><category><![CDATA[editorconfig]]></category><category><![CDATA[emacs-to-vscode]]></category><dc:creator><![CDATA[Bhanuka Mallawaarachchi]]></dc:creator><pubDate>Fri, 14 Mar 2025 19:56:57 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1741981685729/a843b35a-e8b5-43f2-9069-a30302754eca.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-why-emacs-keybindings">Why Emacs Keybindings?</h2>
<p>I've always preferred <strong>Emacs-style editing</strong>, especially the way it handles cursor movement and text manipulation. Even though I have switched to using VSCode for most of my development work, I often found myself missing the intuitive keybindings from Emacs.</p>
<p>Initially, I tried manually configuring my keybindings in VSCode, but this became tedious. Every time I reinstalled VSCode or set up a new machine, I had to manually copy over my settings or sync them using vscode settings sync feature. This led me to think: <strong>what if I packaged my keybindings into a VSCode extension?</strong></p>
<h2 id="heading-the-idea-automating-my-keybinding-setup">The Idea: Automating My Keybinding Setup</h2>
<p>Rather than relying on syncing my settings, I decided to create a <strong>self-contained VSCode extension</strong> that would automatically apply my preferred Emacs-like shortcuts. This way, I could install it on any machine with a single command, and it would just work.</p>
<h2 id="heading-building-the-extension">Building the Extension</h2>
<h3 id="heading-setting-up-the-project">Setting Up the Project</h3>
<p>To create a VSCode extension, I used the official Yeoman generator:</p>
<pre><code class="lang-sh">npx yo code
</code></pre>
<p>This guided me through setting up a basic extension. Since my extension was just about keybindings, I didn’t need to write any actual JavaScript or TypeScript code—just modifying the <code>package.json</code> file was enough.</p>
<h3 id="heading-defining-keybindings">Defining Keybindings</h3>
<p>In <code>package.json</code>, I added my custom keybindings under the <code>contributes.keybindings</code> section. Here’s an example of what it looked like:</p>
<pre><code class="lang-json"><span class="hljs-string">"contributes"</span>: {
  <span class="hljs-attr">"keybindings"</span>: [
    {
      <span class="hljs-attr">"key"</span>: <span class="hljs-string">"ctrl+a"</span>,
      <span class="hljs-attr">"command"</span>: <span class="hljs-string">"cursorHome"</span>,
      <span class="hljs-attr">"when"</span>: <span class="hljs-string">"editorTextFocus"</span>
    },
    {
      <span class="hljs-attr">"key"</span>: <span class="hljs-string">"ctrl+e"</span>,
      <span class="hljs-attr">"command"</span>: <span class="hljs-string">"cursorEnd"</span>,
      <span class="hljs-attr">"when"</span>: <span class="hljs-string">"editorTextFocus"</span>
    }
  ]
}
</code></pre>
<p>This mapped <code>Ctrl+A</code> to <code>cursorHome</code> (move cursor to the beginning of a line) and <code>Ctrl+E</code> to <code>cursorEnd</code> (move cursor to the end of a line), mimicking Emacs behavior.</p>
<h2 id="heading-why-this-was-worth-it">Why This Was Worth It</h2>
<p>Now, instead of manually managing keybindings across machines, I can just search for my extension on VSCode and install it.</p>
<p>This has <strong>saved me time</strong> and made my VSCode setup much more portable. Plus, since it’s on the marketplace, <strong>other Emacs users can benefit from it too!</strong></p>
<h2 id="heading-whats-next">What’s Next?</h2>
<p>Publishing my first VSCode extension was easier than I expected, despite the initial hurdles. Now, I’m thinking about:</p>
<ul>
<li><p><strong>Exploring more about VSCode extension development</strong> and seeing what other customizations I can make.</p>
</li>
<li><p><strong>Exploring the possibility of building different extensions</strong> to further customize my VSCode workflow.</p>
</li>
</ul>
<p>If you're interested in customizing your VSCode experience, I highly recommend trying to write your own extension—it's simpler than you might think!</p>
<h2 id="heading-get-the-extension">Get the Extension</h2>
<p>You can find my extension on the VSCode Marketplace. Let me know if you find it useful!</p>
<p><a target="_blank" href="https://marketplace.visualstudio.com/items?itemName=bhanuka.bmax-emacs">https://marketplace.visualstudio.com/items?itemName=bhanuka.bmax-emacs</a></p>
]]></content:encoded></item><item><title><![CDATA[Linking Libraries Locally with CMake: A Follow-Up]]></title><description><![CDATA[In my previous post about building C/C++ projects with CMake, I shared a simple CMakeLists.txt setup for compiling a basic project. Today, I’ll dive into a specific need that many developers encounter: linking libraries directly from project folders ...]]></description><link>https://imbmax.com/linking-libraries-locally-with-cmake-a-follow-up</link><guid isPermaLink="true">https://imbmax.com/linking-libraries-locally-with-cmake-a-follow-up</guid><category><![CDATA[C]]></category><category><![CDATA[C++]]></category><category><![CDATA[CMake]]></category><category><![CDATA[#Linking]]></category><category><![CDATA[Compiling]]></category><category><![CDATA[raylib]]></category><dc:creator><![CDATA[Bhanuka Mallawaarachchi]]></dc:creator><pubDate>Sun, 27 Oct 2024 04:44:53 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1730003979822/7d5bd640-2121-4f85-847a-730117e716fd.webp" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In my <a target="_blank" href="https://imbmax.com/building-c-or-c-projects-is-not-that-hard">previous post</a> about building C/C++ projects with CMake, I shared a simple CMakeLists.txt setup for compiling a basic project. Today, I’ll dive into a specific need that many developers encounter: linking libraries directly from project folders rather than relying on a system-wide installation. Why Link Libraries Locally?</p>
<p>Sometimes, you might want to keep your dependencies within your project directory, whether for portability, version control, or simply to avoid installing extra packages globally. Here’s how I set this up with CMake. Updated CMakeLists.txt Example for Local Libraries</p>
<p>This is the setup I use to link Raylib (a popular C library for game development) directly from my <code>libs</code> folder.</p>
<pre><code class="lang-bash">cmake_minimum_required(VERSION 3.29)
project(Game)

<span class="hljs-comment"># Set the C++ standard version</span>
<span class="hljs-built_in">set</span>(CMAKE_CXX_STANDARD 20)

<span class="hljs-comment"># Include and link directories for Raylib (in ./libs folder)</span>
include_directories(<span class="hljs-string">"./libs/raylib-5.0_linux_amd64/include"</span>)
link_directories(<span class="hljs-string">"./libs/raylib-5.0_linux_amd64/lib"</span>)

add_executable(Game main.cpp)

<span class="hljs-comment"># Link dynamically to Raylib </span>
<span class="hljs-comment"># Comment this if you are going with static linking</span>
target_link_libraries(Game PRIVATE raylib) 

<span class="hljs-comment"># Uncomment the following line if you prefer static linking</span>
<span class="hljs-comment"># target_link_libraries(cppray PRIVATE raylib.a)</span>
</code></pre>
<h3 id="heading-key-points">Key Points:</h3>
<ul>
<li><p>include_directories: Adds headers for Raylib.</p>
</li>
<li><p>link_directories: Adds the path to the Raylib library files.</p>
</li>
<li><p>target_link_libraries: Specifies whether you’re linking dynamically or statically (toggle as needed).</p>
</li>
</ul>
<h2 id="heading-revisiting-the-previous-approach">Revisiting the Previous Approach</h2>
<p>In the first post, I used target_link_libraries(Game raylib) without specifying local paths, assuming a system-wide installation. While that approach is simpler, linking libraries from subdirectories can be more portable, especially for sharing projects or working across different environments.</p>
]]></content:encoded></item><item><title><![CDATA[Why I Switched to VSCode]]></title><description><![CDATA[Some time ago, I wrote a post about using Vim to look cool and why that’s not a good idea. Now, funny enough, here I am—having switched to VSCode after years of hopping between Vim and Emacs. This isn’t one of those "Vim sucks, I'm going back to VSCo...]]></description><link>https://imbmax.com/why-i-switched-to-vscode</link><guid isPermaLink="true">https://imbmax.com/why-i-switched-to-vscode</guid><category><![CDATA[editor-hopping]]></category><category><![CDATA[text-editor-hopping]]></category><category><![CDATA[vim]]></category><category><![CDATA[Emacs]]></category><category><![CDATA[vscode]]></category><category><![CDATA[Text Editors]]></category><category><![CDATA[text editor]]></category><category><![CDATA[emacs-to-vscode]]></category><dc:creator><![CDATA[Bhanuka Mallawaarachchi]]></dc:creator><pubDate>Wed, 23 Oct 2024 17:58:58 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1729706109154/a98f8a1b-5ee5-48fc-abe3-baa8996709b9.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Some time ago, I wrote a post about using Vim to look cool and why that’s not a good idea. Now, funny enough, here I am—having switched to VSCode after years of hopping between Vim and Emacs. This isn’t one of those "Vim sucks, I'm going back to VSCode" moments, but more of a reflection on how my needs and priorities have shifted.</p>
<h2 id="heading-the-vim-and-emacs-journey">The Vim and Emacs Journey</h2>
<p>I started using Vim around 2017 and absolutely loved the modal editing and the fact that I could do everything right from the terminal. It felt almost like a superpower! But then, around 2022, I got curious about Emacs. For a while, I was all in. Emacs has some fantastic features—like compilation mode, Dired (the file manager), and Magit—that really stood out to me. Plus, it’s fully keyboard-driven without the complexity of Vim’s modal editing. Yes, I said it! While I totally get that modal editing in Vim is super efficient, it’s not the only way to edit text. After switching to Emacs, I found myself really enjoying non-modal editing a lot.</p>
<p>But here's the thing: I kept going back and forth between Vim and Emacs because, as much as I loved Emacs, it wasn’t perfect. For starters, its community is a lot smaller than Vim's, which made it tough to get some niche JavaScript tooling working. For example, getting LSP set up in Yarn PnP projects was a bit of a battle. But let’s not dive into that too much! I managed to set everything up, but it was a bit of a struggle and not exactly a pleasant experience.</p>
<p>Through all this, I realized that non-modal editing actually suits me better. That’s one of the reasons I kept gravitating back to Emacs, even though things weren’t always smooth sailing.</p>
<h2 id="heading-is-emacs-really-that-bad"><strong>Is</strong> Emacs <strong>Really That Bad?</strong></h2>
<p>Sure, there are some downsides to Emacs. The smaller community means certain tools don’t have as much widespread support, but it really depends on what you're using it for. For example, there's a stronger Emacs community for languages like Common Lisp, Racket, Haskell, etc. So if you're working with those technologies, Emacs might just be the best choice, honestly.</p>
<h2 id="heading-why-i-switched-to-vscode">Why I Switched to VSCode</h2>
<p>Don’t get me wrong; I enjoyed customizing my setup in Vim and Emacs, but I didn’t want to go back to Vim because I’m just not a fan of modal editing anymore. So, I decided it was finally time to give VSCode a shot. I added Sublime keybindings (which I loved before my Vim days) and sprinkled in some of my own keybindings inspired by Emacs.</p>
<p>With VSCode, things just work. I’m using those Sublime keybindings, and the few tweaks I’ve made make it feel just right. It’s nice to have something functional right out of the box.</p>
<p>Now, that’s not to say VSCode is perfect. It’s not fully keyboard-driven like Emacs, but honestly, I’ve come to appreciate using the mouse when I need to. Plus, the modern UI is pretty nice—I didn’t think I’d care about that, but it’s grown on me.</p>
<h2 id="heading-looking-back-at-my-vim-to-look-cool-post">Looking Back at My "Vim to Look Cool" Post</h2>
<p>Reflecting on my old post about learning Vim to look cool, I can say that switching to VSCode now isn’t about looking cool or following a trend either. I’ve just shifted to what works best for me right now. Every editor has its strengths and weaknesses, and what really matters is finding the one that helps you be productive and enjoy your work.</p>
<h2 id="heading-exploring-other-options">Exploring Other Options</h2>
<p>I tried Zed, and while it’s interesting, I just don’t feel like it’s ready for prime time use yet, at least for me.</p>
<p>I’ve also thought about WebStorm. I’ve used it in the past, and it was a great IDE, but since I dabble in multiple languages for fun, I need something that works across the board. To do that with JetBrains tools, I’d have to pay for the whole suite, and while I’m fine with paying for WebStorm, I’m not exactly eager to shell out for the entire package. So, for now, that leaves me with VSCode.</p>
<p>And honestly, VSCode isn’t that bad for me after all. It works with minimal effort on my part; it’s mostly about installing a few plugins. Plus, those Sublime + Emacs-inspired keybindings are pretty nice. Sure, it’s not as keyboard-driven as Emacs, but it works for me at the moment.</p>
<h2 id="heading-looking-ahead">Looking Ahead</h2>
<p>Who knows where I’ll go from here? Will I switch to WebStorm? Will I find a way to love Vim’s modal editing again? If that happens, I’ll probably install one of the Vim extensions for VSCode since I really appreciate the low configuration required now.</p>
<p>One thing is for sure: I’ll keep using tools that I enjoy and that inspire me to keep doing what I love, which is writing code.</p>
]]></content:encoded></item><item><title><![CDATA[Portable emacs config without crazy load time]]></title><description><![CDATA[Imagine you can just use package-install to install any Emacs package and have a painless way to reinstall the same packages when you move to a new system.
usually what happens is when you install some package, Emacs modifies your custom-set-variable...]]></description><link>https://imbmax.com/portable-emacs-config-without-crazy-load-time</link><guid isPermaLink="true">https://imbmax.com/portable-emacs-config-without-crazy-load-time</guid><category><![CDATA[Emacs]]></category><category><![CDATA[Linux]]></category><category><![CDATA[automation]]></category><category><![CDATA[lisp]]></category><dc:creator><![CDATA[Bhanuka Mallawaarachchi]]></dc:creator><pubDate>Fri, 04 Oct 2024 14:59:12 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1728055677865/28a682e8-c42a-45fb-ad28-75070a9da1d9.webp" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Imagine you can just use <code>package-install</code> to install any Emacs package and have a painless way to reinstall the same packages when you move to a new system.</p>
<p>usually what happens is when you install some package, Emacs modifies your <code>custom-set-variables</code> block to include the newly installed package in the <code>package-selected-packages</code> variable. But this does not anything special to install these packages on a new system (as far as I know). So when you are on a new system you still have to manually install all the packages present in this block to get your Emacs running without any issues.</p>
<p>So I wrote a script that I can just run on a new system which would read the <code>package-selected-packages</code> variable and install all the relevant packages for me.</p>
<p>Let's go over how to get this set up.</p>
<h3 id="heading-step-1-have-a-separate-custom-file">Step 1: have a separate <code>custom-file</code></h3>
<p>Add the following to your Emacs config to make sure the auto-generated <code>custom-set-variables</code> block is saved to a separate file.</p>
<pre><code class="lang-lisp">(<span class="hljs-name">setq</span> custom-file <span class="hljs-string">"~/.emacs.d/custom.el"</span>)
(<span class="hljs-name">load</span> custom-file)
</code></pre>
<h2 id="heading-step-2-create-the-eslip-script-to-do-the-package-installation">Step 2: Create the eslip script to do the package installation</h2>
<p>Create a file called <code>sync.el</code> in your Emacs configuration folder with the following contents.</p>
<pre><code class="lang-lisp">(<span class="hljs-name">require</span> 'package)

(<span class="hljs-name">load-file</span> <span class="hljs-string">"~/.emacs.d/custom.el"</span>)
(<span class="hljs-name">print</span> package-selected-packages)
<span class="hljs-comment">;; Add melpa</span>
(<span class="hljs-name">add-to-list</span> 'package-archives
             '(<span class="hljs-string">"melpa-stable"</span> . <span class="hljs-string">"https://melpa.org/packages/"</span>) <span class="hljs-literal">t</span>)

(<span class="hljs-name">package-initialize</span>)
<span class="hljs-comment">;; refresh packages</span>
(<span class="hljs-name">setq</span> my/package-refreshed-p <span class="hljs-literal">nil</span>)
(<span class="hljs-name">defun</span> my/refresh-contants ()
    (<span class="hljs-name">unless</span> my/package-refreshed-p
      (<span class="hljs-name">progn</span>
    (<span class="hljs-name">package-refresh-contents</span>)
    (<span class="hljs-name">setq</span> my/package-refreshed-p <span class="hljs-literal">t</span>))))

(<span class="hljs-name">dolist</span> (<span class="hljs-name">pkg</span> package-selected-packages)
  (<span class="hljs-name">condition-case</span> err
      (<span class="hljs-name">progn</span>
    (<span class="hljs-name">let</span> ((<span class="hljs-name">pkg-name</span> (<span class="hljs-name">symbol-name</span> pkg)))
      (<span class="hljs-name">eval</span> (<span class="hljs-name">if</span> (<span class="hljs-name">package-installed-p</span> pkg)
            (<span class="hljs-name">print</span> (<span class="hljs-name">concat</span> pkg-name <span class="hljs-string">" already installed!"</span>))
          (<span class="hljs-name">progn</span>
            (<span class="hljs-name">print</span>  (<span class="hljs-name">concat</span>  <span class="hljs-string">"Installing: "</span> pkg-name))
            (<span class="hljs-name">my/refresh-contants</span>)
            (<span class="hljs-name">package-install</span> pkg))))))
    (<span class="hljs-name">error</span>
     (<span class="hljs-name">message</span> <span class="hljs-string">"Failed to install package: %s. Error: %s"</span> pkg err))))
</code></pre>
<p>This script will go through all the packages listed in <code>package-selected-packages</code> and install any that aren’t already on the system.</p>
<p>The key thing here: we don’t call this script during regular Emacs startup. That means <code>package-refresh-contents</code> is <strong>never</strong> called when Emacs is starting up normally. So no extra load times! You only run this <code>sync.el</code> script when setting up a new system or installing your packages. The rest of the time, Emacs stays fast as usual.</p>
<h2 id="heading-step-3-create-a-shell-file-to-run-the-elisp-script-without-launching-emacs">Step 3: Create a shell file to run the elisp script without launching Emacs</h2>
<ul>
<li>Create an empty file with the following contents for example in ~/.emacs.d/sync</li>
</ul>
<pre><code class="lang-bash"><span class="hljs-meta">#!/bin/bash</span>
emacs -q --script ~/.emacs.d/sync.el
</code></pre>
<ul>
<li>Make it executable:</li>
</ul>
<pre><code class="lang-bash">$ sudo chmod +x ~/.emacs.d/sync
</code></pre>
<p>That’s it! Now, running <code>~/.emacs.d/sync</code> will install any packages listed in your <code>custom-set-variables</code> block.</p>
<h1 id="heading-conclusion">Conclusion</h1>
<p>This technique is actually inspired by Doom Emacs. Alternatively, you could use <code>use-package</code> with <code>:ensure t</code> to handle package installation automatically. But honestly, I find that approach makes your config pretty beefy when you have a lot of packages. Adding a <code>use-package</code> block for everything feels clunky. And yeah, it might avoid the need for this script, but I like the simplicity of just listing the packages and not having to write a bunch of boilerplate.</p>
<p>This setup works perfectly for me—it's lightweight, avoids the usual slowdowns, and gets my Emacs ready in no time!</p>
]]></content:encoded></item><item><title><![CDATA[Ruby without Rails]]></title><description><![CDATA[Ruby on Rails is a great web framework that powers awesome websites like Shopify, GitHub, Basecamp, HEY.com, and more.
This blog post is not to say that Rails is bad or anything like that.
I recently got really inspired to give Ruby a real try after ...]]></description><link>https://imbmax.com/ruby-without-rails</link><guid isPermaLink="true">https://imbmax.com/ruby-without-rails</guid><category><![CDATA[Ruby]]></category><category><![CDATA[Text Editors]]></category><dc:creator><![CDATA[Bhanuka Mallawaarachchi]]></dc:creator><pubDate>Sat, 21 Sep 2024 17:32:39 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1726939738598/57bdb801-ef32-47a1-8e80-3959cc91db45.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Ruby on Rails is a great web framework that powers awesome websites like Shopify, GitHub, Basecamp, <a target="_blank" href="http://HEY.com">HEY.com</a>, and more.</p>
<p>This blog post is not to say that Rails is bad or anything like that.</p>
<p>I recently got really inspired to give Ruby a real try after watching an interview and some talks by DHH, the creator of Ruby on Rails. In those talks, he shares how much joy he finds in programming with Ruby. I can totally relate to things he says, like “a text-editor-friendly programming language (no IDE required)” and “programming for the sheer joy of programming”, etc.</p>
<p>So, I wanted to give Ruby a real shot and started the “Try Ruby” tutorial on the official Ruby website. Midway through the tutorial, I got curious about what it would take to do some web programming with Ruby. I ended up discovering how to build a simple web server using Ruby. Below is the simplest web server implementation in Ruby, so future me won’t have to ask some AI about this again.</p>
<h3 id="heading-the-simplest-hello-world-web-server">The simplest hello world web-server</h3>
<pre><code class="lang-ruby"><span class="hljs-keyword">require</span> <span class="hljs-string">'webrick'</span>

<span class="hljs-comment"># Define the server and specify the port</span>
server = WEBrick::HTTPServer.new(<span class="hljs-symbol">Port:</span> <span class="hljs-number">3000</span>)

<span class="hljs-comment"># Define a main route</span>
server.mount_proc <span class="hljs-string">'/'</span> <span class="hljs-keyword">do</span> <span class="hljs-params">|req, res|</span>
  res.body = <span class="hljs-string">'Hello, world!'</span>
<span class="hljs-keyword">end</span>

<span class="hljs-comment"># Ctrl+C to shut down the server cleanly</span>
trap <span class="hljs-string">'INT'</span> <span class="hljs-keyword">do</span>
  server.shutdown
<span class="hljs-keyword">end</span>

<span class="hljs-comment"># Start the server</span>
server.start
</code></pre>
<h3 id="heading-one-step-further-using-erb-templates">One step further: Using erb templates</h3>
<pre><code class="lang-ruby"><span class="hljs-keyword">require</span> <span class="hljs-string">'webrick'</span>
<span class="hljs-keyword">require</span> <span class="hljs-string">'erb'</span>

server = WEBrick::HTTPServer.new(<span class="hljs-symbol">Port:</span> <span class="hljs-number">3000</span>)

<span class="hljs-comment"># Define an ERB template</span>
template = <span class="hljs-string">&lt;&lt;-HTML
  &lt;html&gt;
    &lt;body&gt;
      &lt;h1&gt;My name is &lt;%= name %&gt;!&lt;/h1&gt;
      &lt;p&gt;The current time is: &lt;%= Time.now %&gt;&lt;/p&gt;
    &lt;/body&gt;
  &lt;/html&gt;
HTML</span>

server.mount_proc <span class="hljs-string">'/'</span> <span class="hljs-keyword">do</span> <span class="hljs-params">|req, res|</span>
  <span class="hljs-comment"># Define variables for the ERB template</span>
  name = <span class="hljs-string">"Bmax"</span>

  <span class="hljs-comment"># Render the ERB template with variables</span>
  renderer = ERB.new(template)
  res.body = renderer.result(binding)

  <span class="hljs-comment"># Specify content type as HTML</span>
  res.content_type = <span class="hljs-string">'text/html'</span>
<span class="hljs-keyword">end</span>

trap <span class="hljs-string">'INT'</span> <span class="hljs-keyword">do</span>
  server.shutdown
<span class="hljs-keyword">end</span>

server.start
</code></pre>
<h3 id="heading-final-step-using-external-erb-template">Final step: Using external erb template</h3>
<pre><code class="lang-ruby"><span class="hljs-comment"># server.rb</span>
<span class="hljs-keyword">require</span> <span class="hljs-string">'webrick'</span>
<span class="hljs-keyword">require</span> <span class="hljs-string">'erb'</span>

server = WEBrick::HTTPServer.new(<span class="hljs-symbol">Port:</span> <span class="hljs-number">3000</span>)

index = File.read(<span class="hljs-string">'index.html'</span>)

server.mount_proc <span class="hljs-string">'/'</span> <span class="hljs-keyword">do</span> <span class="hljs-params">|req, res|</span>
  name = <span class="hljs-string">"Bmax"</span>
  renderer = ERB.new(index)
  res.body = renderer.result(binding)

  res.content_type = <span class="hljs-string">'text/html'</span>
<span class="hljs-keyword">end</span>

trap <span class="hljs-string">'INT'</span> <span class="hljs-keyword">do</span>
  server.shutdown
<span class="hljs-keyword">end</span>

server.start
</code></pre>
<pre><code class="lang-xml"><span class="hljs-comment">&lt;!--index.erb--&gt;</span>  
<span class="hljs-tag">&lt;<span class="hljs-name">html</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>My name is <span class="hljs-tag">&lt;<span class="hljs-name">%=</span> <span class="hljs-attr">name</span> %&gt;</span>!<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>The current time is: <span class="hljs-tag">&lt;<span class="hljs-name">%=</span> <span class="hljs-attr">Time.now</span> %&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span>
</code></pre>
]]></content:encoded></item><item><title><![CDATA[Emacs `gql` template literals highlighting]]></title><description><![CDATA[This code is copied form emacs stack-exchange and adopted to work with web-mode for future reference.
Following is the link to the original stack exchange post:
https://emacs.stackexchange.com/questions/37918/how-to-highlight-graphql-template-literal...]]></description><link>https://imbmax.com/setting-up-emacs-to-have-gql-template-literals-highlights</link><guid isPermaLink="true">https://imbmax.com/setting-up-emacs-to-have-gql-template-literals-highlights</guid><category><![CDATA[Emacs]]></category><category><![CDATA[GraphQL]]></category><category><![CDATA[Text Editors]]></category><dc:creator><![CDATA[Bhanuka Mallawaarachchi]]></dc:creator><pubDate>Wed, 28 Aug 2024 15:47:53 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1724860250799/cc4211fe-12fe-4907-bb7c-7f5821b25e88.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>This code is copied form emacs stack-exchange and adopted to work with web-mode for future reference.</p>
<p>Following is the link to the original stack exchange post:</p>
<p><a target="_blank" href="https://emacs.stackexchange.com/questions/37918/how-to-highlight-graphql-template-literals-gql-in-jsx-files">https://emacs.stackexchange.com/questions/37918/how-to-highlight-graphql-template-literals-gql-in-jsx-files</a></p>
<p>step1: Install the packages</p>
<pre><code class="lang-haskell"><span class="hljs-type">M</span>-x package-install <span class="hljs-type">RET</span> graphql-mode
<span class="hljs-type">M</span>-x package-install <span class="hljs-type">RET</span> mmm-mode
</code></pre>
<p>step2 : Put this in your config</p>
<pre><code class="lang-lisp"><span class="hljs-comment">;; Graphql</span>
(<span class="hljs-name">require</span> 'graphql-mode)
(<span class="hljs-name">require</span> 'mmm-mode)

(<span class="hljs-name">mmm-add-classes</span>
    '((js-graphql
          :submode graphql-mode
          :face mmm-declaration-submode-face
          :front <span class="hljs-string">"[^a-zA-Z]gql`"</span> ;; regex to find the opening tag
          :back <span class="hljs-string">"`"</span>))) <span class="hljs-comment">;; regex to find the closing tag</span>
<span class="hljs-comment">;; mode in the next line can be any major mode that you use for the particular file</span>
<span class="hljs-comment">;; The original answer from stackexchanged had js-mode,</span>
<span class="hljs-comment">;; I have replaced it with web-mode is that's what I use</span>
(<span class="hljs-name">mmm-add-mode-ext-class</span> 'web-mode <span class="hljs-literal">nil</span> 'js-graphql) 
(<span class="hljs-name">setq</span> mmm-global-mode 'maybe)
<span class="hljs-comment">;; Optional configuration that hides the background color for a highlighted block</span>
<span class="hljs-comment">;; I find it useful for debugging emacs, but when actually coding I dont want so much emphasis on submodes</span>
(<span class="hljs-name">setq</span> mmm-submode-decoration-level <span class="hljs-number">0</span>)
</code></pre>
]]></content:encoded></item><item><title><![CDATA[Vim Fuzzy file search and navigation without plugins]]></title><description><![CDATA[Recently, I got curious about how Vim’s built-in commands handle file finding and navigation. Even though I was using modern fuzzy finding plugins at the time, I decided to explore Vim’s native mechanisms. To my surprise, I started enjoying the simpl...]]></description><link>https://imbmax.com/vim-fuzzy-file-search-and-navigation-without-plugins</link><guid isPermaLink="true">https://imbmax.com/vim-fuzzy-file-search-and-navigation-without-plugins</guid><category><![CDATA[fuzzy-file]]></category><category><![CDATA[vim]]></category><category><![CDATA[fuzzy search]]></category><category><![CDATA[neovim]]></category><category><![CDATA[Linux]]></category><category><![CDATA[Text Editors]]></category><category><![CDATA[text editor]]></category><category><![CDATA[vimawesome]]></category><category><![CDATA[vimrc]]></category><category><![CDATA[minimalism]]></category><dc:creator><![CDATA[Bhanuka Mallawaarachchi]]></dc:creator><pubDate>Sun, 25 Aug 2024 15:04:01 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1724598024421/b17ff5cf-14eb-4f05-814e-bf2ec62b6d9d.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Recently, I got curious about how Vim’s built-in commands handle file finding and navigation. Even though I was using modern fuzzy finding plugins at the time, I decided to explore Vim’s native mechanisms. To my surprise, I started enjoying the simplicity and effectiveness of these built-in tools.</p>
<p>If you prefer to see these tips in action, check out the video linked at the end of this post!</p>
<h3 id="heading-using-find-for-fuzzy-searching">Using <code>:find</code> for Fuzzy Searching</h3>
<p>By default, the <code>:find</code> command in Vim requires the full path of the file you want to open. For instance, you might type <code>:find src/parser/parser.odin</code>.</p>
<p>Here’s a handy trick: if you set the <code>path</code> option to <code>**</code>, Vim will search through all directories from your current working directory. You can do this by adding the following line to your <code>.vimrc</code>:</p>
<pre><code class="lang-bash"><span class="hljs-built_in">set</span> path=**
</code></pre>
<p>With this setting, <code>:find</code> becomes much more flexible. For example, if you type <code>:find par</code> and hit Tab, Vim will suggest files that match “par” anywhere in your directory. It’s a simple way to perform fuzzy searches without extra plugins.</p>
<h3 id="heading-navigating-buffers-with-buffer">Navigating Buffers with <code>:buffer</code></h3>
<p>To switch between open files, you can use the <code>:buffer</code> command (or just <code>:b</code>). Suppose you have these files open:</p>
<ul>
<li><p><code>src/parser/parser.odin</code></p>
</li>
<li><p><code>src/main.odin</code></p>
</li>
<li><p><code>src/tokenizer/tokenizer.odin</code></p>
</li>
</ul>
<p>Typing <code>:b to</code> and pressing Enter will take you to the buffer that matches the input. In this case it’ll open the <code>src/tokenizer/tokenizer.odin</code> file. It’s a straightforward method for navigating between your open files.</p>
<h3 id="heading-enjoying-the-simplicity">Enjoying the Simplicity</h3>
<p>As I started using these built-in commands more, I found them to be quite effective. They offer a simple and efficient way to search and navigate files and buffers without relying on additional plugins.</p>
<h3 id="heading-vertical-completion-menu">Vertical Completion Menu</h3>
<p>If you prefer a vertical completion menu, similar to what you might see in Neovim, you can enable it in Vim by setting <code>wildoptions</code> to <code>pum</code>. Unlike Neovim, this isn’t the default in Vim. Add this to your <code>.vimrc</code>:</p>
<pre><code class="lang-bash"><span class="hljs-built_in">set</span> wildoptions=pum
</code></pre>
<h3 id="heading-conclusion">Conclusion</h3>
<p>Exploring Vim’s built-in file finding and navigation features has been a rewarding experience. By adjusting <code>:find</code> and using <code>:buffer</code>, you can navigate and manage your files effectively with just the default tools.</p>
<p>You can see these techniques in action in the video below.</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://youtu.be/xxSLNxPK4ew?si=QZ1-6YuNOMT0UUBk">https://youtu.be/xxSLNxPK4ew?si=QZ1-6YuNOMT0UUBk</a></div>
<p> </p>
<p>Happy Vimming!</p>
]]></content:encoded></item><item><title><![CDATA[How to use Xephyr for Window Manager Development]]></title><description><![CDATA[To future me:
You don't need to install Arch Linux on your laptop or buy a new laptop or install it on a vm to try window management development. Xephyr is just enough for testing the basics. Just make sure you press Ctrl + Shift to lock focus when t...]]></description><link>https://imbmax.com/how-to-use-xephyr-for-window-manager-development</link><guid isPermaLink="true">https://imbmax.com/how-to-use-xephyr-for-window-manager-development</guid><category><![CDATA[Xephyr]]></category><category><![CDATA[xinit]]></category><category><![CDATA[startx]]></category><category><![CDATA[Window Managers]]></category><category><![CDATA[Linux]]></category><dc:creator><![CDATA[Bhanuka Mallawaarachchi]]></dc:creator><pubDate>Sun, 30 Jun 2024 06:37:59 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1719731090053/76095def-badd-4a1e-afdc-ade4ffe8b69e.webp" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>To future me:</p>
<p>You don't need to install Arch Linux on your laptop or buy a new laptop or install it on a vm to try window management development. Xephyr is just enough for testing the basics. Just make sure you press Ctrl + Shift to lock focus when trying to do any binding in the window manager been tested.</p>
<p>The most basic command to start the window manager in a nested session is to do something like</p>
<pre><code class="lang-bash">startx i3 -- /usr/bin/Xephyr :1
<span class="hljs-comment"># with specifying window size</span>
startx i3 -- /usr/bin/Xephyr -screen 800x500 :1
</code></pre>
<p>just make sure to use the full path to the Xephyr.</p>
<p>Above method works, but most of the times when you are just starting out you may not have a way to launch apps inside the window manager. For that using a keybinding agent like sxhkd will be very useful. To do that we need to be able to run other programs besides the window manager while launching.</p>
<p>To do that we can use a xinitrc to add the programs we need to launch.</p>
<p>so we can create a xinitrc file with the following content.</p>
<pre><code class="lang-bash">sxhkd ~/.config/sxhkd/sxhkdrc &amp;
xterm &amp; <span class="hljs-comment"># also launching a terminal just in case</span>
<span class="hljs-comment"># assuming the window manager</span>
<span class="hljs-comment"># executable is called main and is in the current directory</span>
<span class="hljs-built_in">exec</span> ./main
</code></pre>
<p>then you can also have another script to call xinit and open Xephyr with the relevant options</p>
<pre><code class="lang-bash"><span class="hljs-meta">#!/bin/sh</span>

<span class="hljs-built_in">set</span> -e
<span class="hljs-comment">#!/bin/sh</span>

<span class="hljs-built_in">set</span> -e
make <span class="hljs-comment"># just calling make to build the project once more,</span>
<span class="hljs-comment"># so we can just use this one script to just build and run</span>
XEPHYR=$(<span class="hljs-built_in">which</span> Xephyr)
xinit ./xinitrc -- \
    <span class="hljs-string">"<span class="hljs-variable">$XEPHYR</span>"</span> \
    :100 \
    -ac \
    -screen 800x500 \
    -host-cursor
</code></pre>
]]></content:encoded></item><item><title><![CDATA[Learn Computer Science for free!]]></title><description><![CDATA[Everything you want to learn about Computer Science
Useful links:
https://cs.ossu.dev/
https://github.com/ossu/computer-science
https://ossu.firebaseapp.com/#/]]></description><link>https://imbmax.com/learn-computer-science-for-free</link><guid isPermaLink="true">https://imbmax.com/learn-computer-science-for-free</guid><category><![CDATA[learn]]></category><category><![CDATA[Computer Science]]></category><category><![CDATA[#ComputerScienceEducation]]></category><category><![CDATA[education]]></category><dc:creator><![CDATA[Bhanuka Mallawaarachchi]]></dc:creator><pubDate>Tue, 28 May 2024 15:48:07 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/FO7JIlwjOtU/upload/f6a492f3d24e8cfc20bc18bc647dbb31.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Everything you want to learn about Computer Science</p>
<p>Useful links:</p>
<p><a target="_blank" href="https://cs.ossu.dev/">https://cs.ossu.dev/</a></p>
<p><a target="_blank" href="https://github.com/ossu/computer-science">https://github.com/ossu/computer-science</a></p>
<p><a target="_blank" href="https://ossu.firebaseapp.com/#/">https://ossu.firebaseapp.com/#/</a></p>
]]></content:encoded></item><item><title><![CDATA[Why I created a typing practice app]]></title><description><![CDATA[TL;DR: So, I got this itch to type faster, switched from QWERTY to Dvorak, and thought, why not build my own typing practice app? Inspired by a friend's advice on muscle memory, I added cool features like tweaking word counts. It's a work in progress...]]></description><link>https://imbmax.com/why-i-created-a-typing-practice-app</link><guid isPermaLink="true">https://imbmax.com/why-i-created-a-typing-practice-app</guid><category><![CDATA[Typing test, test, typing, online computer typing test, ]]></category><category><![CDATA[typing]]></category><category><![CDATA[typing test]]></category><category><![CDATA[typing speed]]></category><category><![CDATA[Typing tools]]></category><category><![CDATA[React]]></category><category><![CDATA[tools]]></category><category><![CDATA[side project]]></category><category><![CDATA[Developer]]></category><dc:creator><![CDATA[Bhanuka Mallawaarachchi]]></dc:creator><pubDate>Sun, 28 Jan 2024 06:19:54 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1706422117399/a300145f-1e74-4fd2-8ab3-69446a913faa.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>TL;DR: So, I got this itch to type faster, switched from QWERTY to Dvorak, and thought, why not build my own typing practice app? Inspired by a friend's advice on muscle memory, I added cool features like tweaking word counts. It's a work in progress, but hey, check it out at <a target="_blank" href="http://type.imbmax.com">type.imbmax.com</a> – my little typing haven! 🚀</p>
<p>I have always been a fan of touch typing and exploring different keyboards, layouts, etc.</p>
<p>I learned how to touch type in QWERTY around 2006-2007 and used a bunch of online tools back then too.</p>
<p>I currently use Dvorak as my main keyboard layout, and my typing speed varies between 60 to 70 on most online typing tests. I can reach around 90 if I reduce the time or the number of words for a test down to 10, but that's not really what I want.</p>
<p>However, there are a lot of people who can type past the 100 WPM mark. I once asked somebody what the secret to getting really fast at typing was. They said something like, "think of a word you can type really fast already. Type it really fast - muscle memory, like a roll of ASDF. Apply this feel to a bunch of more words," which totally makes sense.</p>
<p>So, I started my mission to increase word speed, and to do that, I wanted some custom features for my typing practice apps. What better way to do that than writing my own, right? :)</p>
<p>I kept thinking about the logic for displaying a typing test interface for something similar to MonkeyType. In the shower, it hit me. I cracked the code, went back to my laptop before bed, and started writing some code. I got the basic typing test display working in about 1 or 2 hours. The next morning, before work, I added indicators for words per minute and test duration, and I already had something usable.</p>
<p>That night, I added a settings page which only supports changing the word count. This was also an important feature I wanted. It allows reducing the word count down to one word, so I get to measure my WPM on a more granular level and identify where I struggle.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1706422670759/130e5cfe-56c9-4a16-bbfc-49d2ece97416.png" alt class="image--center mx-auto" /></p>
<p>I still don't have all the features I want, and it's not finalized by any means. But I'm really happy about having a small side project like this that I can keep improving bit by bit, every now and then. So, I hosted it under a subdomain (<a target="_blank" href="http://type.imbmax.com">type.imbmax.com</a>) for now.</p>
]]></content:encoded></item><item><title><![CDATA[How to access postgresql DB running inside a docker via terminal]]></title><description><![CDATA[First make sure you have postgresql-client installed:
sudo apt-get install postgresql-client

Next, you need to find the IP address of the Docker container running PostgreSQL. You can do this by running the following command:
docker inspect -f '{{ran...]]></description><link>https://imbmax.com/how-to-access-postgresql-db-running-inside-a-docker-via-terminal</link><guid isPermaLink="true">https://imbmax.com/how-to-access-postgresql-db-running-inside-a-docker-via-terminal</guid><category><![CDATA[PostgreSQL]]></category><category><![CDATA[shorts]]></category><category><![CDATA[Docker]]></category><category><![CDATA[terminal]]></category><dc:creator><![CDATA[Bhanuka Mallawaarachchi]]></dc:creator><pubDate>Sun, 28 Jan 2024 05:15:47 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1706083549057/9c6eee86-4763-452d-ad4e-4d2a32073597.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>First make sure you have postgresql-client installed:</p>
<pre><code class="lang-plaintext">sudo apt-get install postgresql-client
</code></pre>
<p>Next, you need to find the IP address of the Docker container running PostgreSQL. You can do this by running the following command:</p>
<pre><code class="lang-plaintext">docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' &lt;container_name&gt;
</code></pre>
<p>Once you have the IP address, you can connect to the PostgreSQL instance using the <code>psql</code> command. Run the following command in your terminal:</p>
<pre><code class="lang-plaintext">psql -h &lt;ip_address&gt; -U &lt;username&gt; -d &lt;database_name&gt;
</code></pre>
]]></content:encoded></item><item><title><![CDATA[Build multiple OCaml executables in one Dune Project]]></title><description><![CDATA[Create a dune project
Follow these steps to create a new dune project if you don't already have one.

First, initiate the project structure.
  dune init project foo


It will create a project structure like this


  The bin folder contains the source...]]></description><link>https://imbmax.com/build-multiple-ocaml-executables-in-one-dune-project</link><guid isPermaLink="true">https://imbmax.com/build-multiple-ocaml-executables-in-one-dune-project</guid><category><![CDATA[ocaml]]></category><category><![CDATA[Dune]]></category><dc:creator><![CDATA[Bhanuka Mallawaarachchi]]></dc:creator><pubDate>Mon, 21 Aug 2023 15:30:40 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1703051355216/b861be00-b0ac-4f13-b217-457fc361fc85.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h3 id="heading-create-a-dune-project">Create a dune project</h3>
<p>Follow these steps to create a new dune project if you don't already have one.</p>
<ul>
<li><p>First, initiate the project structure.</p>
<pre><code class="lang-bash">  dune init project foo
</code></pre>
</li>
<li><p>It will create a project structure like this</p>
</li>
<li><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1692630925329/e373f499-bbfd-4945-859c-7eba141f1b07.png" alt class="image--center mx-auto" /></p>
<p>  The bin folder contains the source file for the main executable <code>main.ml</code></p>
</li>
<li><p>the <code>bin/dune</code> file has the build instruction for the executable, it'll look something like this.</p>
<pre><code class="lang-lisp">  (<span class="hljs-name">executable</span>
   (<span class="hljs-name">public_name</span> foo)
   (<span class="hljs-name">name</span> main)
   (<span class="hljs-name">libraries</span> foo))
</code></pre>
</li>
</ul>
<h3 id="heading-adding-support-to-build-multiple-executables">Adding Support to build multiple executables</h3>
<ul>
<li><p>Let's see how to add support to build another executable called bar, which we'll write in the file called <code>bar.ml</code>.</p>
</li>
<li><p>First, create a file called <code>bar.ml</code> in the <code>bin</code> directory.</p>
</li>
<li><p>Then you can update the <code>bin/dune</code> file support multiple executables like below.</p>
<pre><code class="lang-lisp">  (<span class="hljs-name">executables</span>
   (<span class="hljs-name">public_names</span> foo bar)
   (<span class="hljs-name">name</span> main bar)
   (<span class="hljs-name">libraries</span> foo))
</code></pre>
</li>
</ul>
<h3 id="heading-build-and-run-the-different-executable">Build and run the different executable</h3>
<p>You can use the following commands to run the different executables.</p>
<pre><code class="lang-bash">dune <span class="hljs-built_in">exec</span> ./bin/main.exe
dune <span class="hljs-built_in">exec</span> ./bin/bar.exe
</code></pre>
<p>To build you can run following</p>
<pre><code class="lang-bash">dune build ./bin/main.exe
dune build ./bin/bar.exe
</code></pre>
<p>To run the built executables</p>
<pre><code class="lang-bash"> ./_build/default/bin/main.exe
 ./_build/default/bin/bar.exe
</code></pre>
]]></content:encoded></item><item><title><![CDATA[Emacs-Inspired Search in Vim]]></title><description><![CDATA[I wanted to share some in-buffer search techniques that I brought back to my Neovim setup from my year of experience with Emacs.
You know how you can use "/" and "?" to perform forward and backward searches for text in the current buffer. Similarly, ...]]></description><link>https://imbmax.com/emacs-inspired-search-in-vim</link><guid isPermaLink="true">https://imbmax.com/emacs-inspired-search-in-vim</guid><category><![CDATA[vim]]></category><category><![CDATA[neovim]]></category><category><![CDATA[Emacs]]></category><dc:creator><![CDATA[Bhanuka Mallawaarachchi]]></dc:creator><pubDate>Sat, 01 Jul 2023 04:51:16 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1703051714603/dbe920eb-2441-4863-b62a-60279619dd43.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I wanted to share some in-buffer search techniques that I brought back to my Neovim setup from my year of experience with Emacs.</p>
<p>You know how you can use "/" and "?" to perform forward and backward searches for text in the current buffer. Similarly, in Emacs, you can use Ctrl+s and Ctrl+r to search back and forth. There's a slight difference in how it works in Emacs, though. In Emacs, searching starts immediately as you type Ctrl+s, and the text you type is incrementally added to the current search term. You can achieve the same behavior in Vim with "set <code>incsearch</code>," but there's more. In Emacs, you can keep hitting Ctrl+s and Ctrl+r to continue searching back and forth in the buffer while still editing the search term.</p>
<p>Can we do the same in Vim?</p>
<p>Yes, you can, but it works slightly differently in Vim. When you are in <code>incsearch</code> mode, i.e., once you hit "/" or "?" and start typing a text, you can still edit the text and search back and forth without having to go back to normal mode. The default keys to do that are Ctrl+g (search forward) and Ctrl+t (search backward).</p>
<p>However, this might be a lot to remember, and you may not end up using it even though you know it because of all the keybindings you have to remember.</p>
<p>I have a simpler way to achieve this in my configuration, where I'm able to use Ctrl+s just like in Emacs. Instead of Ctrl+r, I mapped search backward to Alt+s because Ctrl+r is the default keybinding to redo.</p>
<p>The following is what I have in my Neovim config to make this work:</p>
<pre><code class="lang-bash">vim.keymap.set(<span class="hljs-string">'n'</span>, <span class="hljs-string">'&lt;C-s&gt;'</span>, <span class="hljs-string">'/'</span>)
vim.keymap.set(<span class="hljs-string">'c'</span>, <span class="hljs-string">'&lt;C-s&gt;'</span>, <span class="hljs-string">'&lt;C-g&gt;'</span>)
vim.keymap.set(<span class="hljs-string">'n'</span>, <span class="hljs-string">'&lt;A-s&gt;'</span>, <span class="hljs-string">'?'</span>)
vim.keymap.set(<span class="hljs-string">'c'</span>, <span class="hljs-string">'&lt;A-s&gt;'</span>, <span class="hljs-string">'&lt;C-t&gt;'</span>)
</code></pre>
]]></content:encoded></item><item><title><![CDATA[Vim, find and replace across multiple files]]></title><description><![CDATA[One of the main frustrations most vim users has could be doing find and replace operations across multiple files, from within vim.
I will list down few techniques with some use cases.
Use case one: Find and replace a dependency version in multiple pa...]]></description><link>https://imbmax.com/vim-find-and-replace-across-multiple-files</link><guid isPermaLink="true">https://imbmax.com/vim-find-and-replace-across-multiple-files</guid><category><![CDATA[vim]]></category><category><![CDATA[grep]]></category><category><![CDATA[neovim]]></category><category><![CDATA[Linux]]></category><category><![CDATA[editors]]></category><dc:creator><![CDATA[Bhanuka Mallawaarachchi]]></dc:creator><pubDate>Wed, 21 Jun 2023 03:15:11 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1703090879286/e351176c-506f-4f2e-8afa-07302f9374be.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>One of the main frustrations most vim users has could be doing find and replace operations across multiple files, from within vim.</p>
<p>I will list down few techniques with some use cases.</p>
<h3 id="heading-use-case-one-find-and-replace-a-dependency-version-in-multiple-packagejson-files-in-a-monorepo"><strong>Use case one:</strong> Find and replace a dependency version in multiple package.json files in a monorepo.</h3>
<p>Imagine you have a monorepo containing multiple Node.js packages, each with its own package.json file. You want to update the dependency version of "foo" from v3.5 to v4.0 in all package.json files. To achieve this, you can use the following command:</p>
<pre><code class="lang-bash">:args ./**/*package.json
:argdo %s/foo-v3.5/foo-v4.0/
</code></pre>
<p>The <code>args</code> command sets the argument list to the specified files, and the subsequent <code>argdo</code> command runs on each file in the argument list. The <code>argdo %s/foo-v3.5/foo-v4.0/</code> command performs a global search and replaces within the current file, replacing "foo-v3.5" with "foo-v4.0".</p>
<p>This technique is useful when you know all the files that need modification beforehand, as it can be more efficient than the technique used in the next use case.</p>
<h3 id="heading-use-case-two-find-and-replace-a-term-any-term-in-multiple-files">Use case two: find and replace a term any term in multiple files</h3>
<p>Suppose you want to replace all occurrences of "foo" with "bar" in all TypeScript files under the "./src" directory.</p>
<pre><code class="lang-bash">:grep foo ./src/**.ts
:cdo %s/foo/bar
</code></pre>
<p>The <code>grep</code> command searches for the specified pattern in the specified files and outputs a list of matching lines. The subsequent <code>cdo</code> command operates on each line in the list and runs the following <code>%s/foo/bar</code> command. This performs a global search and replace within the current file, replacing "foo" with "bar".</p>
<p>This technique is useful when you don't know all the files that need modification beforehand or when you want to apply changes to specific lines or patterns within files.</p>
<p>In addition to these techniques, Vim offers many more powerful commands for working with multiple files simultaneously. By mastering these commands, you can greatly enhance your productivity as a Vim user.</p>
]]></content:encoded></item><item><title><![CDATA[Release my port! How to Free Up a Used Port in Linux]]></title><description><![CDATA[You're in the middle of some exciting web development, everything's going smoothly, and then—bam! You hit an error message that throws a wrench in your plans:
Error: listen EADDRINUSE: address already in use 0.0.0.0:3022

Okay, so the port you need i...]]></description><link>https://imbmax.com/release-my-port</link><guid isPermaLink="true">https://imbmax.com/release-my-port</guid><category><![CDATA[Linux]]></category><category><![CDATA[Web Development]]></category><category><![CDATA[command line]]></category><dc:creator><![CDATA[Bhanuka Mallawaarachchi]]></dc:creator><pubDate>Thu, 25 May 2023 14:00:39 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1703078147076/32f0a053-cb0d-47bf-9f91-3ca205cb3841.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>You're in the middle of some exciting web development, everything's going smoothly, and then—bam! You hit an error message that throws a wrench in your plans:</p>
<pre><code class="lang-bash">Error: listen EADDRINUSE: address already <span class="hljs-keyword">in</span> use 0.0.0.0:3022
</code></pre>
<p>Okay, so the port you need is already in use. Now what? You decide to ask some AI chatbot for help, hoping it can quickly point you in the right direction.</p>
<p>You type in something like:</p>
<p><em>"Hey robot, how do I find out which process is using a specific port in Linux? I'm getting this</em> <code>EADDRINUSE</code> <em>error for port 3022."</em></p>
<p>And sure enough, the bot does its thing and gives you a simple, clear solution:</p>
<h3 id="heading-step-1-find-the-process-using-the-port">Step 1: Find the Process Using the Port</h3>
<p>Open up your terminal and run:</p>
<pre><code class="lang-bash">$ sudo lsof -i :3022
</code></pre>
<p>This command lists all the processes using port 3022, along with their Process IDs (PIDs). Now you've got the culprit!</p>
<h3 id="heading-step-2-kill-the-process">Step 2: Kill the Process</h3>
<p>Once you have the PID, freeing up the port is as easy as:</p>
<pre><code class="lang-bash">$ sudo <span class="hljs-built_in">kill</span> -9 &lt;PID&gt;
</code></pre>
<p>Just replace <code>&lt;PID&gt;</code> with the actual number from the previous command. If you're not sure about killing a process, you can always try restarting your system or changing the port number your application is trying to use.</p>
<p>With this quick fix, you're back in action and ready to continue your work. Sometimes, a little nudge in the right direction is all you need to solve these annoying little problems.</p>
<p><strong>Closing Thoughts</strong></p>
<p>Running into port conflicts can be a bit frustrating, especially when you’re in the flow of coding. But with a couple of terminal commands, you can easily resolve the issue and get back to what really matters—building and creating. So next time you hit this snag, remember this quick trick!</p>
]]></content:encoded></item><item><title><![CDATA[Emacs as a Time Tracker]]></title><description><![CDATA[Note: This is a post that I published in my blog on September 11, 2021, I'm re-posting it here since I'm planning to continue blogging here.
I have tried many tools and techniques to track time. Tracking time helps me organize a bit better and manage...]]></description><link>https://imbmax.com/emacs-as-a-time-tracker</link><guid isPermaLink="true">https://imbmax.com/emacs-as-a-time-tracker</guid><category><![CDATA[Productivity]]></category><category><![CDATA[Emacs]]></category><category><![CDATA[General Programming]]></category><dc:creator><![CDATA[Bhanuka Mallawaarachchi]]></dc:creator><pubDate>Mon, 22 May 2023 16:05:13 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1684854398158/8b81558e-5fce-49bc-aa8f-67fdcbea96fe.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Note: This is a post that I published in my blog on September 11, 2021, I'm re-posting it here since I'm planning to continue blogging here.</p>
<p>I have tried many tools and techniques to track time. Tracking time helps me organize a bit better and manage my time better. I have tried things like spreadsheets, and different utility Apps, but nothing stuck for more than a couple of days.</p>
<p>The good news is since I switched to Emacs recently, it opened me up to the world of org-mode, which has been pretty useful lately. But before getting to the good stuff I'll list down some of the stuff that I've tried in the past. And as with everything I wanted something keyboard-driven because I like it that way :)</p>
<h2 id="heading-tools-and-techniques-ive-tried-in-the-past">Tools and techniques I've tried in the past</h2>
<h3 id="heading-spreadsheets">Spreadsheets</h3>
<p>Spreadsheets was a no-brainer, it was simple enough for the job. I used to just add the list of tasks and added start and end times on two columns and at the end of the day, with the help of a few formulas, I was able to see stuff like time spent on different tasks and the total time, etc.</p>
<p>This was fine but wasn't perfect.</p>
<h3 id="heading-project-hamster-gtk-timetakerhttpsgithubcomprojecthamsterhamster-gtk"><a target="_blank" href="https://github.com/projecthamster/hamster-gtk">Project hamster GTK timetaker</a></h3>
<p>This was a good app, but it only runs on Linux, but I needed something cross-platform.</p>
<h3 id="heading-manual-text-or-mark-down-files">Manual text or Mark-down files</h3>
<p>This was a perfect solution for my itch for using the keyboard, because this, I can do in my editor. But the downside is that, text files can't really do more than just holding onto what I put in them, thus, no easy way to calculate times. End of the day I had to use a spreadsheet again to do the calculations and there's no way to quickly check the time I've spent on the current task.</p>
<h2 id="heading-here-comes-the-org-mode">Here comes the Org Mode</h2>
<p>So now I'm on Emacs, I've heard all the good stuff about org-mode, but soon I found out that I haven't heard it all :). My plan on capturing times on org-mode was to have an org table and insert times on that and figure out how to do calculations on org tables and you know the drill. But this was a very naive attempt at using org-mode for tracking time and I hated it. After trying that, I knew there were only two ways it was going to end up: either all the buzz about org-mode managing your life stuff is made up, emacs fan-boy stories, or I didn't know enough. Luckily it turned out to be the latter :).</p>
<h3 id="heading-time-tracking-for-real-in-org-mode">Time tracking for real in Org Mode</h3>
<p>So I watched a few more YouTube videos and figured how it's done. I discovered the Org clock which was the real deal, it allows to clock in and out on org-mode document items.</p>
<p><strong>Here's how I use it</strong>:</p>
<ul>
<li><p>Add the beginning of the day, I create a list of tasks I'll work on that day on a new org file.</p>
</li>
<li><p>Then as I start each task, I just take the cursor over to the tasks name then call <code>org-clock-in</code> ( which is set to <code>SPC m c i</code> in Doom emacs )</p>
</li>
<li><p>Every time I clock in, it just adds a new click entry to the current task and adds an end entry to the previously active clock entry.</p>
</li>
<li><p>And I create add a clock report at the top of the org file calling <code>org-lock-report</code>. The report shows a summary of time spent on each task.</p>
</li>
</ul>
<p><strong>A sample org file with time tracking and clock report:</strong></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1684775279372/c972c5f5-0240-43c2-8f7e-32692709a518.png" alt class="image--center mx-auto" /></p>
<p>This actually fits really well in my workflow, I'll list down some of the pros below.</p>
<ul>
<li><p><strong>It's Emacs all the way</strong> Having time tracking inside my editor mean no switching between multiple Apps, and no new key bindings to learn. I can just treat my time tracker as another text file and edit anything on it using the same musle memory I use for any other editing.</p>
</li>
<li><p><strong>No more manual counting</strong></p>
</li>
</ul>
<p>Although it's just a text file, org-mode give these features like real-time status, at any given time I can see the total time I've spent on the current task on the mini buffer. And there is also <code>org-update-all-dblock</code> macro, which updates all the <code>org-clock-report(s)</code> that's in the current buffer (yes, the report is not real-time, need to run that macro to update, but hey it's just one macro, no drama!! 😊)</p>
<h3 id="heading-so-is-this-it-is-it-the-ultimate-time-tracker">So is this it? is it the ultimate time tracker?</h3>
<p>Well, this is the technique or tool which I stuck for this long. It's been two weeks now since I've started using it and it's been the most satisfying time tracker I've used till now. No big complaints here, as I said, it fits nicely within my workflow, but I wished the report was more autonomous, also I wished if there was a little bit more ease in clocking in and out. I mean, I could set a different key binding for that, but what I'm trying to say is, the overall experience could improve a bit more.</p>
<h3 id="heading-do-i-recommend-it-to-everyone">Do I recommend it to everyone?</h3>
<p>Yes and No!!, I mean if you are already using Emacs, I don't have to recommend it, you might already be using it or maybe something better than that, but if not, I highly recommend giving it a shot. But I don't recommend it for non-Emacs users. I think learning Emacs just to use the org-mode time tracking feature is a big undertaking, which may not be worth of your time (well, depends on your own valuation of time :) ), and it won't be satisfying either, because you have no other use of Emacs :). It's perfect for me (at least for now), because I'm using Emacs as my editor.</p>
]]></content:encoded></item><item><title><![CDATA[Vim to Lisp to Emacs]]></title><description><![CDATA[Note: This is a post that I published in my blog on August 23, 2021, I'm re-posting it here since I'm planning to continue blogging here.
Also, I'm now back on Neovim, after using Emacs for a full year, I might write a follow-up post sometime later.
...]]></description><link>https://imbmax.com/vim-to-lisp-to-emacs</link><guid isPermaLink="true">https://imbmax.com/vim-to-lisp-to-emacs</guid><category><![CDATA[vim]]></category><category><![CDATA[Emacs]]></category><category><![CDATA[IDEs]]></category><category><![CDATA[Text Editors]]></category><category><![CDATA[lisp]]></category><dc:creator><![CDATA[Bhanuka Mallawaarachchi]]></dc:creator><pubDate>Mon, 22 May 2023 15:44:28 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1703084463454/575d8fea-9d2a-4339-b0e3-4689298cd8b4.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Note: This is a post that I published in my blog on August 23, 2021, I'm re-posting it here since I'm planning to continue blogging here.</p>
<p>Also, I'm now back on Neovim, after using Emacs for a full year, I might write a follow-up post sometime later.</p>
<p>TLDR:</p>
<blockquote>
<p>I was happily using vim (neovim), then one day I discovered Lisp,<br />a week later I switched to Emacs</p>
</blockquote>
<p>I had been using Vim since 2017. At first, I had vscode as a backup for when I had to do some major code refactoring, but around mid-2020, I decided to go fully Vim and never turned back, until one day…</p>
<h2 id="heading-a-vim-confession">A Vim Confession</h2>
<p>Although I had been using Vim to a religious level, I felt the need for something more rich from time to time. Following are some of the pain points I had with it.</p>
<ul>
<li><strong>No proper GUI</strong></li>
</ul>
<p>Now don't get me wrong, I don't enjoy clicking around with the mouse all day, I want to keep using the keyboard as my primary input device, but we keyboard lovers mostly end up spending most of our time on the terminal emulators because there isn't much GUI software built with the keyboard in mind. I think that's where things have gone wrong, GUI doesn't mean we have to lose the convenience of doing things with the keyboard. I use a lot of terminal-related utils, but I fancy a nice Gui version of Vim.</p>
<ul>
<li><strong>Viml and Lua</strong></li>
</ul>
<p>Yes, vim and Neovim have bindings for a lot of languages for plugin development, but to do basic config stuff you need to deal with either vim or Lua. Yes, lua is simple, it's easier to understand and write, but I just don't enjoy Lua much.</p>
<h3 id="heading-vim-emulation-on-other-editors">Vim Emulation on other editors</h3>
<p>In the past, I have tried a few other editors/IDEs with vim emulation, like vs code, web storm, and sublime. For the most part vim style editing works fine but as soon as I try to work with multiple files, I'll have to go back to using the mouse at some point, which I don't really enjoy while writing code.</p>
<p>The main reason for that is the fact that unlike Vim none of those editors were built to operate with just a keyboard. But I always knew there was this other editor which was keyboard-driven just like Vim, more on that later.</p>
<h2 id="heading-trying-emacs">Trying Emacs</h2>
<p>So if other editors don't cut it, it must be Emacs right, emacs was built with the keyboard in mind, it came around the same time as Vim. Also, I have heard all the stories about people switching to Emacs because of how awesome org-mode was or Magit (a popular git client implementation on Emacs), but I also none of that is going to make me use Emacs if it can't give me the same experience while writing code. So I thought I'd give it a try.</p>
<p>I have tried Vanila Emacs and its built-in tutorial before, but I never liked the default keybindings that came with it. I also didn't want to spend a lot of hours in Emacs to learn how to configure. I have heard of these prebuilt distributions of Emacs, I wanted to try one of those to see if Emacs can do what I want. If it works then I can learn how to config it later.</p>
<p>Two major such distributions I've heard of were Spacemacs and Doom. I didn't like the layer system in Spacemacs, so I decided to try Doom Emacs.</p>
<p>Immediately after trying it I had these issues:</p>
<ul>
<li><p>Doom emacs was slow to me compared to Vim.</p>
</li>
<li><p>I still need to configure stuff to get it to a usable state for my taste, Evil mode (vim emulation) was good but it wasn't perfect.</p>
</li>
<li><p>File navigation</p>
</li>
</ul>
<p>On Vim I just use Netrw to go into nearby files, I used "-" to open it and use j, k, h, l to navigate through it (this is not the default behavior, I had my Vim configured that way). But I just didn't know who to make Dired (Emacs's default file browser) to do that.</p>
<p>After a few hours of trying Doom Emacs, I wasn't interested enough in going further with it, because I wasn't that impressed with performance or Elisp (the language used to configure Emacs).</p>
<p>So I decided that Emacs wasn't for me, part of me secretly still wanted to try Emacs, but my weekend was over, and I didn't want to spend any more time on it, then I turned back to Neovim, vim is the best editor in the world.</p>
<h2 id="heading-the-story">The Story</h2>
<p>As a programming language enthusiast, I spend a lot of time learning about different languages, maybe more time than I really should. So, I have come across Lisp many times, but it was something I was never interested in because I always thought it was just some set of languages only used at some abstract mathematical theory level.</p>
<h3 id="heading-fennel">Fennel</h3>
<p>My first encounter with Lisp in action was watching vim conf 2019, I saw this language called Fennel, a Lisp that compiles to Lua. It can be used to configure Neovim, basically, it can be used in any place where Lua can be used. That was interesting but I didn't try it because it was lisp</p>
<h3 id="heading-finally-trying-out-fennel">Finally, trying out Fennel</h3>
<p>On a one fine Sunday evening, I just thought of finally checking out Fennel, just because I was fed up with Lua, and I wanted to give a refresh to my Neovim config, I thought I'd try this Fennel lisp thing to see how far it goes, (hint: lisp did came very far although fennel didn't ).</p>
<p>So I started to explore a little bit of fennel side-by-side with Lua. I started writing stuff in Fennel and watching the Lua output on a second split of my editor. To this date, I can't articulate the feeling I got as I was watching that process. I was amazed by how I was able to generate so much lua with very little fennel, and very little syntax. If you know Lisp, you know there's not much syntax to it, it's just mostly all lists, but the output on the Lua side was ugly, no blame on the compiler, it's just what Lua is, it's not pretty in my eyes.</p>
<h3 id="heading-exploring-more-about-lisp">Exploring more about Lisp</h3>
<p>After being marveled by watching Fennel, I wanted to find out more about this Lisp thing, so I went on youtube and started watching a lot of videos on Lisp. One of the talks I watched referred me to this other talk called <a target="_blank" href="https://www.youtube.com/watch?v=oytL881p-nQ">Simple made easy</a> by Rich Hitchkey the creator of the Clojure programming language. I kind of bought into what he said in that video, "Simple constructs make it easy to build better solutions" (this may be not what he exactly said, but something around that, at least that's how I understood it).</p>
<p>So with this new mind said when I look back at lisp, I felt it, I felt that since lisp is so simple, maybe it makes it for crafting better software. And then I also thought about these stories about how Emacs has better packages (the equivalent of plugins in Vim world) compared to the similar counterparts in Vim. And even there have been innovative things like org-mode, which only first came in the Emacs world. And then I saw some more non-Emacs stuff that was built with Lisp.</p>
<p>It was still that same Sunday I rediscovered fennel, and I couldn't sleep well that night, I had a lot of lisp dreams, I was going to try all these new lisp stuff next weekend. There was suddenly a lot I wanted to try and find out more about, things like more fennel, Clojure, Clojure script, Common Lisp, and a big endless list of stuff.</p>
<h3 id="heading-trying-doom-emacs-again">Trying Doom Emacs again</h3>
<p>The next week I kept watching more youtube videos on Lisp in the evenings, and because a lot of Lisp programmers use Emacs, I saw a lot of Emacs stuff too. By around Thursday, I couldn't resist the urge to try Emacs again. And I tried it, this time though, I was fully armed to write some lisp, and I was able to configure Dired to work similarly to how Netrw worked in my Vim configuration.</p>
<p>Dired configuration:</p>
<pre><code class="lang-bash">;; binding <span class="hljs-keyword">for</span> going up a directory with <span class="hljs-string">"h"</span> <span class="hljs-keyword">in</span> dired
(map! :map dired-mode-map :n <span class="hljs-string">"h"</span> <span class="hljs-comment">#'dired-up-directory)</span>
(map! :map dired-mode-map :n <span class="hljs-string">"l"</span> <span class="hljs-comment">#'dired-find-file)</span>

(after! dired
  (map! :n <span class="hljs-string">"-"</span> <span class="hljs-string">'dired-jump))

;; show simple list without the all the ls -al stuff
(add-hook! dired-mode
    (dired-hide-details-mode))</span>
</code></pre>
<p>That was it, that's all the Elisp code I had to add to get Dired to behave the way I wanted it to, this was pretty straightforward, I know I'm using the doom emacs macros, but it gets the job done. By this time I was pretty impressed by the fact that I was just able to configure emacs to be more like I needed it to be.</p>
<p>So I decided to spend that evening playing a bit more with Emacs and coding a bit more to see what was missing, after hours and about a few more lines of Elisp, I had Doom emacs working, very similar to my tmux + vim setup.</p>
<p><strong>But wasn't Doom emacs slow?</strong></p>
<p>I didn't care anymore, I existed in this new lisp-driven environment, and I didn't want to lose it. Yes, it took like a few more milliseconds to open a file sometimes, but not all the time, but with that and a few lines of configuration I was getting a lot more.</p>
<h2 id="heading-in-conclusion">In Conclusion</h2>
<p>In the past, I was running away from emacs because of Lisp and also because I was so in love with Vim. But Lisp got me chasing behind Emacs this time around. And now I'm also using all the other good stuff which came with Emacs. I'm using Magit for most of my git work. I'm becoming an org-mode junky. I'm tracking my time on it, taking my notes on it, and even writing this blog post on an org file. And also, I'm working on my own Emacs configuration on the side as I find time so that I don't have to depend on Doom config.</p>
<h3 id="heading-is-emacs-the-best-text-editor-in-the-world-now">Is Emacs the best text editor in the world now?</h3>
<p>No!!, In my opinion, that place is still for Vim, then why Emacs? because Emacs is overall a better software and an extendable interactive development environment, yes, by design, it's made for extendibility. I'm still using Vim key bindings for almost all the editing I do inside Emacs. I have even mapped Ctrl+u to do page up, but I think that's a big no-no in Emacs world because Ctrl+d has some special meaning in Emacs, I may or may not change that in the future, but that's what I have for now.</p>
<h3 id="heading-so-was-vim-a-mistake-would-it-have-been-better-if-i-had-started-with-emacs-itself">So was Vim a mistake? would it have been better if I had started with Emacs itself?</h3>
<p>I don't think so, as I said, figuring out how to get productive with Emacs was a bit hard at first. I don't think I'd have taken this big of a leap if I hadn't started with Vim to begin with. So I'm glad I started there.</p>
<p><strong>This is it!!</strong></p>
<p>I can write this post forever and never publish it, so I'm going to end it here, I'll write more about this new experience in the future.</p>
]]></content:encoded></item><item><title><![CDATA[Building c or c++ projects is not that hard (with cmake)]]></title><description><![CDATA[One of the main reasons for a lot of people to give up learning c or c++ is it's hard to figure out the build system. This is a problem that both new and experienced developer face alike.
I used to use gnu make by writing my Makefile(s) by hand, and ...]]></description><link>https://imbmax.com/building-c-or-c-projects-is-not-that-hard</link><guid isPermaLink="true">https://imbmax.com/building-c-or-c-projects-is-not-that-hard</guid><category><![CDATA[C]]></category><category><![CDATA[C++]]></category><category><![CDATA[CMake]]></category><category><![CDATA[#Linking]]></category><dc:creator><![CDATA[Bhanuka Mallawaarachchi]]></dc:creator><pubDate>Sun, 21 May 2023 16:57:11 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1720879422793/a791ebfb-35a5-44c8-96c5-2249dafb8665.webp" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>One of the main reasons for a lot of people to give up learning c or c++ is it's hard to figure out the build system. This is a problem that both new and experienced developer face alike.</p>
<p>I used to use gnu make by writing my Makefile(s) by hand, and I have tried a little bit of premake which is a build system written in Lua. I knew that cmake should be the easiest solution, but I always found it very intimidating to learn how to use cmake.</p>
<p>So here's the simplest cmake file you can create.</p>
<p>(this content should go into a file called <code>CMakeLists.txt</code>)</p>
<pre><code class="lang-c"># <span class="hljs-function">Specify the minimum version of cmake to use
<span class="hljs-title">cmake_minimum_required</span><span class="hljs-params">(VERSION <span class="hljs-number">3.0</span>)</span>

# Specify the name of the executable
<span class="hljs-title">project</span><span class="hljs-params">(Game)</span>

<span class="hljs-meta"># list all the source files next to the executable name</span>
<span class="hljs-title">add_executable</span><span class="hljs-params">(Game main.c)</span>

# Add <span class="hljs-keyword">this</span> line <span class="hljs-keyword">if</span> cmake complains about <span class="hljs-keyword">not</span> being able to find your <span class="hljs-title">library</span> <span class="hljs-params">(in <span class="hljs-keyword">this</span> <span class="hljs-keyword">case</span> raylib)</span>
<span class="hljs-title">find_package</span><span class="hljs-params">(raylib)</span>
# Add any external dependencies
<span class="hljs-title">target_link_libraries</span><span class="hljs-params">(Game raylib)</span></span>
</code></pre>
<p>you can build your project in a build folder by issuing the following commands in the terminal.</p>
<pre><code class="lang-bash">$ mkdir build
$ <span class="hljs-built_in">cd</span> ./build
$ cmake ..
$ make
</code></pre>
]]></content:encoded></item></channel></rss>