<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Meliq Pilosyan</title>
    <description>The latest articles on DEV Community by Meliq Pilosyan (@melopilosyan).</description>
    <link>https://dev.to/melopilosyan</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1242817%2Fc339eabe-ca92-4e68-89d1-4cb57ad2c422.jpeg</url>
      <title>DEV Community: Meliq Pilosyan</title>
      <link>https://dev.to/melopilosyan</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/melopilosyan"/>
    <language>en</language>
    <item>
      <title>From FZF file preview to a browser for cht.sh to discovering the ideal solution</title>
      <dc:creator>Meliq Pilosyan</dc:creator>
      <pubDate>Thu, 12 Dec 2024 20:22:40 +0000</pubDate>
      <link>https://dev.to/melopilosyan/from-fzf-file-preview-to-a-browser-for-chtsh-to-discovering-the-ideal-solution-3ann</link>
      <guid>https://dev.to/melopilosyan/from-fzf-file-preview-to-a-browser-for-chtsh-to-discovering-the-ideal-solution-3ann</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Very few scientific discoveries, if any, ever begin with "Eureka".&lt;br&gt;
It's "that's funny ...".&lt;br&gt;
  — Isaac Asimov (possibly (&lt;a href="https://youtu.be/6J66WQOmYYg?si=dktgrezQ6i5TdycZ&amp;amp;t=941" rel="noopener noreferrer"&gt;paraphrased by Neil deGrasse Tyson&lt;/a&gt;))&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;em&gt;A story about the cycle of learning, following a hunch, further exploration and discovery along the way.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;After setting up the FZF to my liking: &lt;a href="https://github.com/melopilosyan/confNest/blob/main/bash/rc.d/fzf.sh" rel="noopener noreferrer"&gt;changing the theme&lt;/a&gt;, &lt;a href="https://github.com/melopilosyan/confNest/blob/main/bin/fzf-preview.sh" rel="noopener noreferrer"&gt;adding the file preview&lt;/a&gt; and some aliases, I was happily using it until the next time I looked up information on &lt;a href="https://cht.sh/" rel="noopener noreferrer"&gt;cht.sh&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Don't get me wrong, the outcome is more satisfying. It was the feeling of realization that a new project was unfolding right then, sparked by curiosity and excitement.&lt;/p&gt;

&lt;p&gt;You see, the way the cht.sh API is designed with its &lt;code&gt;:list&lt;/code&gt;s of topics and subtopics makes it a perfect candidate for browsing it with FZF.&lt;/p&gt;

&lt;p&gt;It did took me a few iterations to finalize the spec, decide on the trade-offs (I had to say no to supporting some of the cht.sh's  features for the sake simplicity), but in the end I made myself a useful tool. Well, two, actually. So naturally I'm in a happy user mode again.&lt;/p&gt;

&lt;p&gt;Let's start with &lt;a href="https://github.com/melopilosyan/confNest/blob/main/bin/cs" rel="noopener noreferrer"&gt;the browser&lt;/a&gt;. It's a Bash script that takes user input matching the path in the cht.sh URL, downloads the file if not found in the cache, saves it for next time, and displays it with &lt;code&gt;bat&lt;/code&gt; leveraging its conditional pager.&lt;/p&gt;

&lt;p&gt;The fun begins when you run the script without arguments or with one ending with a slash. Now you'll be greeted by FZF with all the predefined topics listed for search and preview, if they have already been downloaded. And if not, Enter on the selected topic downloads it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1y0vrngfvqd7d7nozbdk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1y0vrngfvqd7d7nozbdk.png" alt="The cheat sheet for Ruby searched and previewed in the FZF browser for cht.sh" width="800" height="428"&gt;&lt;/a&gt;&lt;/p&gt;
The cheat sheet for Ruby searched and previewed in the browser



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1cogczgmm510kustunvw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1cogczgmm510kustunvw.png" alt="Bash shortcuts cheat sheet found as a subtopic in the FZF browser for cht.sh" width="800" height="429"&gt;&lt;/a&gt;&lt;/p&gt;
Bash shortcuts cheat sheet found as a subtopic



&lt;p&gt;It includes several convenient features:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Sorting topics so the most recently downloaded ones appear first.&lt;/li&gt;
&lt;li&gt;Reopening FZF with subtopics when selecting/passing a topic that ends with a slash.&lt;/li&gt;
&lt;li&gt;Accepting custom queries directly from the FZF prompt.&lt;/li&gt;
&lt;li&gt;Building a proper URL by escaping the input.&lt;/li&gt;
&lt;li&gt;Printing the full command needed to display a cheat sheet directly, bypassing the need to search through FZF again.&lt;/li&gt;
&lt;li&gt;Lastly, allows to delete cached files or remove the entire cache directory.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo0tltalxx72uwxj6v0dl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo0tltalxx72uwxj6v0dl.png" alt="A fragment of the help message of the FZF browser for cht.sh" width="800" height="657"&gt;&lt;/a&gt;&lt;/p&gt;
A fragment of the help message of the cheat sheets browser



&lt;p&gt;Unsurprisingly, I was using the half-baked browser during its development to look up Bash's variable expansion and substitution syntax, and to refresh my memory on &lt;code&gt;find&lt;/code&gt;, &lt;code&gt;awk&lt;/code&gt;, and &lt;code&gt;sed&lt;/code&gt; parameters. In hindsight, the utility has already begun to serve its purpose. What I didn't expect, however, was to find a candidate for another tool I was looking for in the middle of making this one.&lt;/p&gt;

&lt;p&gt;The cheat sheet for bashmarks is presented as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# bashmarks&lt;/span&gt;
&lt;span class="c"&gt;# Save and jump to commonly used directories using 1 character commands.&lt;/span&gt;
&lt;span class="c"&gt;# More information: &amp;lt;https://github.com/huyng/bashmarks&amp;gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I've tried common directory bookmarking implementations such as &lt;code&gt;zoxide&lt;/code&gt;. But they all seem to override the &lt;code&gt;cd&lt;/code&gt; command, which interferes with other, more important tools in my workflow. Whereas bashmarks has no automated functionality. It's not even a separate binary. But a set of a few straightforward Bash functions to manually add, delete, print and list directory bookmarks. Exactly what I needed.&lt;/p&gt;

&lt;p&gt;I really liked the simplicity of the idea. With my newly acquired Bash skills, it was a no-brainer to copy the file and refine the implementation. I dropped &lt;code&gt;zsh&lt;/code&gt; support and optimized it further for Bash. Added Tab completion and an optional second parameter to specify the directory path when creating new bookmarks. Renamed the &lt;code&gt;g&lt;/code&gt; command to &lt;code&gt;j&lt;/code&gt; and removed &lt;code&gt;p&lt;/code&gt; altogether. Printing the path of a specific bookmark is of no use to me.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp4j5oe69b5ulbkt2iz1j.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp4j5oe69b5ulbkt2iz1j.png" alt="The help message of my version of bashmarks" width="800" height="249"&gt;&lt;/a&gt;&lt;/p&gt;
The help message of the cheat sheets browser



&lt;p&gt;Again, these are just functions that you can update as needed.&lt;/p&gt;

&lt;p&gt;Or refer to &lt;a href="https://github.com/melopilosyan/confNest" rel="noopener noreferrer"&gt;the README of my confNest&lt;/a&gt;, if you'd like to use my version. The README includes installation instructions for both bashmarks and the cheat sheets browser.&lt;/p&gt;




&lt;p&gt;As I wrapped this project up, I couldn't help but reflect on the journey — the progression of curiosity, experimentation, and discovery. It began from the decision to finally integrate the FZF into my workflow. I was curious to unlock its full potential, which led to the idea of combining it with cht.sh. In the process, I found more insights and tools, each enabling the next step.&lt;/p&gt;

&lt;p&gt;It's funny how side projects are born — often out of questioning the status quo, wondering "what if ...".&lt;/p&gt;

</description>
      <category>learning</category>
      <category>tooling</category>
      <category>bash</category>
      <category>cheatsheet</category>
    </item>
    <item>
      <title>The joy of creating your own toolkit</title>
      <dc:creator>Meliq Pilosyan</dc:creator>
      <pubDate>Mon, 12 Feb 2024 15:22:23 +0000</pubDate>
      <link>https://dev.to/melopilosyan/the-joy-of-creating-your-own-toolkit-34fl</link>
      <guid>https://dev.to/melopilosyan/the-joy-of-creating-your-own-toolkit-34fl</guid>
      <description>&lt;p&gt;Are you a Ruby developer? You use Neovim? Then this article is for you. Although the Neovim component is not a hard requirement.&lt;/p&gt;

&lt;p&gt;A while ago (almost two years), tired of switching between &lt;a href="https://sw.kovidgoyal.net/kitty/" rel="noopener noreferrer"&gt;Kitty&lt;/a&gt; windows and inspired by &lt;a href="https://www.youtube.com/watch?v=cf72gMBrsI0" rel="noopener noreferrer"&gt;Tj's excellent tutorial&lt;/a&gt; on how easy it can be to add custom features to Neovim, I wrote a &lt;a href="https://github.com/melopilosyan/rspec-integrated.nvim" rel="noopener noreferrer"&gt;teeny tiny plugin&lt;/a&gt; to run &lt;a href="https://rspec.info/" rel="noopener noreferrer"&gt;RSpec&lt;/a&gt; tests from within &lt;a href="https://neovim.io/" rel="noopener noreferrer"&gt;Neovim&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;It was so much fun figuring out the weirdness of the Lua language that I just loved it. If I didn't know Ruby, I'd agree to program in Lua for full time. And the Neovim aspect only added satisfaction. I felt how the buffers, text lines and words come to life, gain character and preferences after every API discovery.&lt;/p&gt;

&lt;p&gt;Spending years in programming I worked on different kinds of projects, tackled fresh ideas, wrote automation scripts for bizarre use cases, but this project was different. I spent so much time in IDEs that file tabs were just openings, means of entry, nothing that I could relate to. And the source code... I have long ceased to see it as &lt;a href="https://www.youtube.com/watch?v=gd5uJ7Nlvvo" rel="noopener noreferrer"&gt;“plain” text&lt;/a&gt;. Parameters, variables, methods, conditions and expressions, loops and statements, it's all conceptual, intangible.&lt;/p&gt;

&lt;p&gt;Now my script runs underneath that text and the result reflects on top of it, treating lines and words as individual entities. The same kind of text developed in one window does something to a text in another. It was unusual, strange and exciting.&lt;/p&gt;

&lt;p&gt;Unsurprisingly, this plugin was even more fun to use.&lt;/p&gt;

&lt;p&gt;You hit a couple of keys, and watch the thing to test your test assumptions. Sometimes your fingers are still on the keyboard, you still think if that's enough of a test to validate your application code, when the result comes back. A nice green success message on top right corner of your screen or a little "Failure" label at the end of the line where something requires your attention.&lt;/p&gt;

&lt;p&gt;Soon it was hard to tell what I enjoyed most was writing tests or running them. I've made myself a small toy.&lt;/p&gt;




&lt;p&gt;I was happily playing with it for months. Then there was a no-ruby-coding period. And when I came back again, that fast feedback loop didn't seem that fast anymore. Even simplest test examples took 2 to 3 seconds to complete. While RSpec reported tests duration of around 0.3 seconds, the actual command didn't fall below 2.5.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbvi62tclv8mwgnd69pl6.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbvi62tclv8mwgnd69pl6.jpg" alt="Screenshot of RSpec's output running without spring where tests took 0.29, files loaded in 1.76 and the entire command completed in 2.85 seconds" width="800" height="379"&gt;&lt;/a&gt;&lt;/p&gt;
RSpec's runtime without Spring



&lt;p&gt;"Files took 1.76 seconds to load". This refers to the loading of the Rails framework and the application code involved.&lt;/p&gt;

&lt;p&gt;The application I'm using here includes the &lt;a href="https://github.com/rails/spring" rel="noopener noreferrer"&gt;Spring gem&lt;/a&gt;. Opening the Rails console, for example, uses the application running in the background, which is what Spring does. It is fast. A lot less than 2 seconds, at least. But the &lt;code&gt;bundle exec rspec&lt;/code&gt; command that my plugin used has no idea about Spring.&lt;/p&gt;

&lt;p&gt;How I didn't notice this back then is a good question. But from the other hand, 2-3 seconds is not that much. I used to run tests during active development that took minutes. Definitely can wait 2 seconds. Or so I thought, until it started to irritate me.&lt;/p&gt;

&lt;p&gt;It turns out Spring has no native support for the &lt;code&gt;rspec&lt;/code&gt; command. And yet, as is usually the case, there is this gem: &lt;a href="https://github.com/jonleighton/spring-commands-rspec" rel="noopener noreferrer"&gt;spring-commands-rspec&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;So I installed it, generated the &lt;code&gt;bin/rspec&lt;/code&gt; binstub. Here is the effect.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7a9sn5na2odmal4hxxyw.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7a9sn5na2odmal4hxxyw.jpg" alt="Screenshot of RSpec's output running with spring where tests took 0.4, files loaded in 0.17 and the entire command finished in 0.96 seconds" width="800" height="404"&gt;&lt;/a&gt;&lt;/p&gt;
RSpec's runtime with Spring



&lt;p&gt;Total runtime of 2.8 seconds vs 0.9, almost 3 times faster. Impressive!&lt;/p&gt;

&lt;p&gt;Of course, this doesn't mean that Spring will make the whole test suite 3 times faster. The 1-2 seconds difference in loading files disappears within minutes of running the entire test suite. But in the case of running single test examples or individual files over and over during development, it actually can be 2 to 3 times faster.&lt;/p&gt;




&lt;p&gt;I updated my plugin to be a wee bit smarter about selecting which command to run RSpec as, and back to happy mode again.&lt;/p&gt;

&lt;p&gt;In the end, here are a couple of facts about the &lt;code&gt;spring-commands-rspec&lt;/code&gt; gem.&lt;br&gt;
&lt;a href="https://github.com/jonleighton/spring-commands-rspec/blob/master/lib/spring/commands/rspec.rb" rel="noopener noreferrer"&gt;It's minuscule&lt;/a&gt;. So small it's hard to call it a gem.&lt;/p&gt;

&lt;p&gt;1 class with 4 methods with a total of 5 lines of executable code and 2 more lines integrating with Spring. That's it. That's the whole gem.&lt;/p&gt;

&lt;p&gt;But wait. There is more. &lt;a href="https://github.com/jonleighton/spring-commands-rspec" rel="noopener noreferrer"&gt;This code&lt;/a&gt; was last updated ten years ago.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3ucq78t5d05f624rzc5z.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3ucq78t5d05f624rzc5z.jpg" alt="Screenshot of the Github page of spring-commands-rspec gem, showing its updated ten years ago" width="800" height="386"&gt;&lt;/a&gt;&lt;/p&gt;
Github page of the spring-commands-rspec gem



&lt;p&gt;Isn't that fascinating? When was the last time you loaded a ten year old library and it still worked?&lt;/p&gt;

&lt;p&gt;What a great example of the benefits of robust interfaces. Well done Spring!&lt;/p&gt;

</description>
      <category>rspec</category>
      <category>spring</category>
      <category>neovim</category>
    </item>
  </channel>
</rss>
