<?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: Attila Gonda</title>
    <description>The latest articles on DEV Community by Attila Gonda (@pcdevil).</description>
    <link>https://dev.to/pcdevil</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%2F148325%2F0e62a7a3-c29d-4c73-ad9a-7cdd3fa14842.jpeg</url>
      <title>DEV Community: Attila Gonda</title>
      <link>https://dev.to/pcdevil</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/pcdevil"/>
    <language>en</language>
    <item>
      <title>g - a wrapper around git with additional feature extension</title>
      <dc:creator>Attila Gonda</dc:creator>
      <pubDate>Sun, 02 Aug 2020 13:52:07 +0000</pubDate>
      <link>https://dev.to/pcdevil/g-a-wrapper-around-git-with-additional-feature-extension-3m11</link>
      <guid>https://dev.to/pcdevil/g-a-wrapper-around-git-with-additional-feature-extension-3m11</guid>
      <description>&lt;p&gt;I am a longtime CLI fan. I love how the basic Unix commands can be piped through each other to create very robust automation with a few lines of codes.&lt;/p&gt;

&lt;p&gt;I also love &lt;a href="https://git-scm.com" rel="noopener noreferrer"&gt;git&lt;/a&gt;, and I use it almost exclusively from command line. But after the learning curve (which was almost 10 years ago as my colleague introduced it to me), I realised I spend too much time on repetitive commands, and it would be nice to extend it with some handy features too!&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/pcdevil" rel="noopener noreferrer"&gt;
        pcdevil
      &lt;/a&gt; / &lt;a href="https://github.com/pcdevil/g" rel="noopener noreferrer"&gt;
        g
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      a wrapper around git with additional feature extension.
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;g&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;A wrapper around &lt;strong&gt;git&lt;/strong&gt; with additional feature extension
See detailed functionality in the &lt;strong&gt;&lt;a href="https://github.com/pcdevil/g#features" rel="noopener noreferrer"&gt;Features&lt;/a&gt;&lt;/strong&gt; section!&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Table of Contents&lt;/h3&gt;
&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://github.com/pcdevil/g#install" rel="noopener noreferrer"&gt;Install&lt;/a&gt;&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://github.com/pcdevil/g#prerequirements" rel="noopener noreferrer"&gt;Prerequirements&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://github.com/pcdevil/g#steps" rel="noopener noreferrer"&gt;Steps&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://github.com/pcdevil/g#predefined-git-config" rel="noopener noreferrer"&gt;Predefined git config&lt;/a&gt;&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://github.com/pcdevil/g#abbreviation-aliases" rel="noopener noreferrer"&gt;Abbreviation aliases&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://github.com/pcdevil/g#basic-aliases" rel="noopener noreferrer"&gt;Basic aliases&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://github.com/pcdevil/g#commit-aliases" rel="noopener noreferrer"&gt;Commit aliases&lt;/a&gt;&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://github.com/pcdevil/g#conventional-commit-aliases" rel="noopener noreferrer"&gt;Conventional Commit aliases&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://github.com/pcdevil/g#advanced-aliases" rel="noopener noreferrer"&gt;Advanced aliases&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://github.com/pcdevil/g#features" rel="noopener noreferrer"&gt;Features&lt;/a&gt;&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://github.com/pcdevil/g#g-1" rel="noopener noreferrer"&gt;g&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://github.com/pcdevil/g#backup-branch" rel="noopener noreferrer"&gt;backup-branch&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://github.com/pcdevil/g#conventional-commit" rel="noopener noreferrer"&gt;conventional-commit&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://github.com/pcdevil/g#set-user" rel="noopener noreferrer"&gt;set-user&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://github.com/pcdevil/g#super-init" rel="noopener noreferrer"&gt;super-init&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://github.com/pcdevil/g#switch-main" rel="noopener noreferrer"&gt;switch-main&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://github.com/pcdevil/g#license" rel="noopener noreferrer"&gt;License&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Install&lt;/h2&gt;

&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Prerequirements&lt;/h3&gt;

&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;unix-like system&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://git-scm.com" rel="nofollow noopener noreferrer"&gt;git&lt;/a&gt; (minimum: v1.7+, recommended: v2.35+)&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.zsh.org/" rel="nofollow noopener noreferrer"&gt;zsh&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Steps&lt;/h3&gt;

&lt;/div&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Clone the repositoy to a desired folder:&lt;/p&gt;
&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;$ git clone git@github.com:pcdevil/g.git &lt;span class="pl-k"&gt;~&lt;/span&gt;/.g&lt;/pre&gt;

&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Bootstrap it in your &lt;code&gt;.zshrc&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;&lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; Load the init script of g. This will do the followings:&lt;/span&gt;
&lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; - installs the `g` command&lt;/span&gt;
&lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; - adds the project's bin directory to the $PATH&lt;/span&gt;
&lt;span class="pl-c1"&gt;source&lt;/span&gt; &lt;span class="pl-smi"&gt;$HOME&lt;/span&gt;/.g/g.plugin.zsh&lt;/pre&gt;

&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;(Optional) Install &lt;code&gt;gitconfig&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;$ git config --global --add include.path &lt;span class="pl-k"&gt;~&lt;/span&gt;/.g/gitconfig&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;See &lt;a href="https://github.com/pcdevil/g#predefined-git-config" rel="noopener noreferrer"&gt;Predefined git config&lt;/a&gt; section for more information about it.&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Reload the terminal.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Predefined git config&lt;/h2&gt;

&lt;/div&gt;
&lt;p&gt;The project provides an optional &lt;code&gt;gitconfig&lt;/code&gt; to extend the default &lt;strong&gt;git&lt;/strong&gt;
config. Currently it only contains aliases…&lt;/p&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/pcdevil/g" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;On that notion, I created a small tool called &lt;code&gt;g&lt;/code&gt;! It's a long-term project of mine, and contains lot of subjective decisions based on how I use &lt;strong&gt;git&lt;/strong&gt;. I've recently made it public and added better documentation to help anyone who would like to use it :)&lt;/p&gt;

&lt;p&gt;In this post, I'll go through the functionalities to give a high level overview of it!&lt;/p&gt;

&lt;h2&gt;
  
  
  The entry-point
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://git-scm.com/docs/git-status" rel="noopener noreferrer"&gt;&lt;code&gt;git status&lt;/code&gt;&lt;/a&gt; shows information about the current working tree and it's one of the most used &lt;strong&gt;git&lt;/strong&gt; commands. There are several good practices how to make it more accessible with &lt;code&gt;git st&lt;/code&gt;, &lt;code&gt;g st&lt;/code&gt; or &lt;code&gt;gst&lt;/code&gt; aliases, but I found these solutions less intuitive, and made it even simpler: just run the &lt;code&gt;g&lt;/code&gt; command and you'll get the same result while in non-git directories it calls the &lt;a href="https://git-scm.com/docs/git-help" rel="noopener noreferrer"&gt;&lt;code&gt;git help&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The entry-point is not only an alias for the &lt;code&gt;git status&lt;/code&gt;, but it's also a wrapper around &lt;strong&gt;git&lt;/strong&gt; and when it is called with argument, it acts according to them. Other functionalities are based on this behaviour.&lt;/p&gt;

&lt;h2&gt;
  
  
  Aliases
&lt;/h2&gt;

&lt;p&gt;If we talk about &lt;em&gt;how to remove the repetitiveness of &lt;strong&gt;git&lt;/strong&gt; usage&lt;/em&gt;, most of the time the solution is the &lt;a href="https://git-scm.com/book/en/v2/Git-Basics-Git-Aliases" rel="noopener noreferrer"&gt;aliases&lt;/a&gt;. &lt;code&gt;g&lt;/code&gt; provides aliases for common git commands, and some more advanced ones including &lt;a href="https://git-scm.com/docs/git-commit" rel="noopener noreferrer"&gt;&lt;code&gt;git commit&lt;/code&gt;&lt;/a&gt; and &lt;a href="https://git-scm.com/docs/git-merge" rel="noopener noreferrer"&gt;&lt;code&gt;git merge&lt;/code&gt;&lt;/a&gt;!&lt;/p&gt;

&lt;p&gt;See the following table for some hints of the available aliases, while the full list is &lt;a href="https://github.com/pcdevil/g#predefined-git-config" rel="noopener noreferrer"&gt;in the documentation&lt;/a&gt;:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Alias command&lt;/th&gt;
&lt;th&gt;
&lt;strong&gt;git&lt;/strong&gt; command&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;g br&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;git branch&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;g cl&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;git clone&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;g ci-a&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;git commit --amend&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;g ci-as&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;git commit --amend --no-edit&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;g d&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;git diff&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;g me&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;git merge&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;g me-ms&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;git merge --no-ff --no-edit&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;g sh&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;git show&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;g sw&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;git switch&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;g sw-m&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;git switch master&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Moreover, there are also &lt;a href="https://github.com/pcdevil/g#angular-commit-aliases" rel="noopener noreferrer"&gt;angular commit&lt;/a&gt; and &lt;a href="https://github.com/pcdevil/g#advanced-aliases" rel="noopener noreferrer"&gt;advanced&lt;/a&gt; aliases: the first gives shortcut for a below discussed &lt;code&gt;g&lt;/code&gt; feature, while the second consist of a one liner log (&lt;code&gt;g l&lt;/code&gt;), set origin and push the branch to it (&lt;code&gt;g ph-o&lt;/code&gt;), and alternate way to commit where only the message can be specified (&lt;code&gt;g ci&lt;/code&gt;).&lt;/p&gt;

&lt;h2&gt;
  
  
  Added functionalities
&lt;/h2&gt;

&lt;p&gt;While having shortcuts to existing commands is good, &lt;code&gt;g&lt;/code&gt; gives several small utilities to enhance &lt;strong&gt;git&lt;/strong&gt; usage - there are mostly related to bootstrap a repository.&lt;/p&gt;

&lt;h3&gt;
  
  
  Setting the git user
&lt;/h3&gt;

&lt;p&gt;If you are working in an environment where custom e-mail domain is used, and you want to make sure your commits are bound to you nicely, you can use &lt;a href="https://git-scm.com/docs/git-config" rel="noopener noreferrer"&gt;&lt;code&gt;git config&lt;/code&gt;&lt;/a&gt; to set that up.&lt;br&gt;&lt;br&gt;
To achieve the effect you either have to do it locally in every single repository, or only one time globally. The first is troublesome (declaring the name and e-mail in numerous repositories), while the second option eliminates the portability of the config because and you can't put the &lt;code&gt;.gitconfig&lt;/code&gt; in your &lt;em&gt;dotfiles&lt;/em&gt; repository.&lt;/p&gt;

&lt;p&gt;To resolve this, &lt;code&gt;g set-user&lt;/code&gt; (or &lt;code&gt;g su&lt;/code&gt; for short) comes in handy. You only set up the username, email and potentially signing key once as a url-matched configuration, then running the &lt;code&gt;g su&lt;/code&gt; command sets it on the current repository with no hustle!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example setup&lt;/strong&gt;:&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="nv"&gt;$ &lt;/span&gt;git config &lt;span class="nt"&gt;--global&lt;/span&gt; &lt;span class="s1"&gt;'user.https://github.com.email'&lt;/span&gt; &lt;span class="s1"&gt;'jakab@gipsz.eu'&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;git config &lt;span class="nt"&gt;--global&lt;/span&gt; &lt;span class="s1"&gt;'user.https://example.org.email'&lt;/span&gt; &lt;span class="s1"&gt;'jakab.gipsz@example.org'&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;git config &lt;span class="nt"&gt;--global&lt;/span&gt; &lt;span class="s1"&gt;'user.https://example.org.name'&lt;/span&gt; &lt;span class="s1"&gt;'jakab.gipsz'&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;git config &lt;span class="nt"&gt;--global&lt;/span&gt; &lt;span class="s1"&gt;'user.https://example.org.signingkey'&lt;/span&gt; &lt;span class="s1"&gt;'0000000000000042'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Thanks to the url-matched keys, this won't have any effect on your standard config, allowing to &lt;em&gt;symlink&lt;/em&gt; the same config file on several computers.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example usage&lt;/strong&gt;:&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="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;my-project
&lt;span class="nv"&gt;$ &lt;/span&gt;g set-user example.org
&lt;span class="nv"&gt;$ &lt;/span&gt;git config user.name
jakap.gipsz
&lt;span class="nv"&gt;$ &lt;/span&gt;git config user.email
jakab.gipsz@example.org
&lt;span class="nv"&gt;$ &lt;/span&gt;git config user.signingkey
0000000000000042
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here the when the command is called, the author changes accordingly to the config without stating your user information! Full details about how the matching config is found or how the signing key is set is &lt;a href="https://github.com/pcdevil/g#set-user" rel="noopener noreferrer"&gt;in the documentation&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  More delicate cloning
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://github.com/ohmyzsh/ohmyzsh" rel="noopener noreferrer"&gt;Oh My Zsh&lt;/a&gt; provides a &lt;a href="https://github.com/ohmyzsh/ohmyzsh/wiki/Cheatsheet#commands" rel="noopener noreferrer"&gt;&lt;code&gt;take&lt;/code&gt;&lt;/a&gt; command which is basically &lt;code&gt;mkdir &amp;amp;&amp;amp; cd&lt;/code&gt;. The assumption behind the command is after creating a directory you usually want to use too. For the same reason this can be useful for &lt;strong&gt;git&lt;/strong&gt; too, and &lt;code&gt;g&lt;/code&gt; is equipped a command which mimics the original one: &lt;code&gt;g take&lt;/code&gt; (&lt;code&gt;g ta&lt;/code&gt; as alias) clones a repository then changes the current directory into it.&lt;/p&gt;

&lt;p&gt;Running &lt;code&gt;g take&lt;/code&gt; has one more benefit: it runs the &lt;code&gt;g set-user&lt;/code&gt; command after the clone, which makes &lt;code&gt;g take&lt;/code&gt; an end-to-end solution for cloning and immediate usage of a repository.&lt;/p&gt;

&lt;h3&gt;
  
  
  Change directory relative to the root
&lt;/h3&gt;

&lt;p&gt;On bigger projects I often enter a deep sub-directory to perform an action, and afterwards I want to go back to the root directory.&lt;/p&gt;

&lt;p&gt;For that, &lt;code&gt;cd -&lt;/code&gt; can help you to change the current directory to the previous one, but if the current directory was a result of several changes, you need to remember how many changes were executed and pass it to it. &lt;strong&gt;Oh My Zsh&lt;/strong&gt; helps a little bit (see &lt;a href="https://github.com/ohmyzsh/ohmyzsh/wiki/Cheatsheet#directory" rel="noopener noreferrer"&gt;cheatsheet&lt;/a&gt;), but the burden of remembering how much jumping occurred is still present.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;g cd&lt;/code&gt; command helps with this problem:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;With no argument, it acts like &lt;code&gt;cd&lt;/code&gt; and jumps to the &lt;em&gt;home directory&lt;/em&gt; - which is interpreted as the root of the repository&lt;/li&gt;
&lt;li&gt;While passing an argument changes the active directory relative to the root&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Example for given argument&lt;/strong&gt;:&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="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; ~/my-project
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;src/routes/api/categories
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="c"&gt;# do some actions&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;g &lt;span class="nb"&gt;cd test&lt;/span&gt;/routes
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;pwd&lt;/span&gt;
~/my-project/test/routes
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Robust, extensive repository initialisation
&lt;/h3&gt;

&lt;p&gt;Creating a new repository can be tedious:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Init git&lt;/li&gt;
&lt;li&gt;Set up the &lt;a href="https://git-scm.com/docs/gitignore" rel="noopener noreferrer"&gt;gitignore&lt;/a&gt; &lt;em&gt;(and then forget to include a crucial path by accident)&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;Add readme and license files&lt;/li&gt;
&lt;li&gt;Add temp directory&lt;/li&gt;
&lt;li&gt;Create the first commit&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;To make it simpler, I created the &lt;code&gt;g super-init&lt;/code&gt; (with &lt;code&gt;g si&lt;/code&gt; as alias) command to automatise all these steps and make sure I don't forget anything!&lt;/p&gt;

&lt;p&gt;The command has the same procedure as listed above with the following details:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;strong&gt;gitignore&lt;/strong&gt; will be populated with:

&lt;ul&gt;
&lt;li&gt;The output of &lt;a href="https://www.toptal.com/developers/gitignore" rel="noopener noreferrer"&gt;gitignore.io&lt;/a&gt; with Linux, MacOS, Windows, IntelliJ (+all), Vim, and Visual Studio Code related ignores.&lt;/li&gt;
&lt;li&gt;The ignores related to the specified programming language.&lt;/li&gt;
&lt;li&gt;a &lt;code&gt;tmp&lt;/code&gt; directory and a &lt;code&gt;.env&lt;/code&gt; file.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;A &lt;code&gt;README.md&lt;/code&gt; file will be created with the name of the project and the given description (if any).&lt;/li&gt;

&lt;li&gt;A &lt;code&gt;LICENSE.md&lt;/code&gt; file will be created with &lt;a href="https://mit-license.org/" rel="noopener noreferrer"&gt;MIT&lt;/a&gt; license.&lt;/li&gt;

&lt;li&gt;The commit will follow the &lt;a href="https://github.com/angular/angular/blob/master/CONTRIBUTING.md#-commit-message-format" rel="noopener noreferrer"&gt;Angular's Contributing Commit Message Format&lt;/a&gt;, in form of &lt;code&gt;build(&amp;lt;projectname&amp;gt;): initial commit&lt;/code&gt;.&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;Additionally, the &lt;code&gt;g super-init&lt;/code&gt; acts as &lt;code&gt;g take&lt;/code&gt;, meaning it will change the current directory to the new project too.&lt;/p&gt;

&lt;p&gt;The programming language and the descriptions can be specified during invocation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example usage&lt;/strong&gt;:&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="nv"&gt;$ &lt;/span&gt;g super-init my-project node &lt;span class="s2"&gt;"My awesome new project."&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;pwd&lt;/span&gt;
~/my-project

&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;ls&lt;/span&gt; &lt;span class="nt"&gt;-1A&lt;/span&gt;
.git
.gitignore
LICENSE.md
README.md
tmp

&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;tail&lt;/span&gt; &lt;span class="nt"&gt;-6&lt;/span&gt; .gitignore
&lt;span class="c"&gt;# End of https://www.toptal.com/developers/gitignore/api/linux,macos,windows,node,intellij+all,vim,visualstudiocode&lt;/span&gt;

&lt;span class="c"&gt;### Project ###&lt;/span&gt;
/tmp/&lt;span class="k"&gt;**&lt;/span&gt;
&lt;span class="o"&gt;!&lt;/span&gt;/tmp/.gitkeep
.env

&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;cat &lt;/span&gt;README.md
&lt;span class="c"&gt;# my-project&lt;/span&gt;
My awesome new project.

&lt;span class="c"&gt;## License&lt;/span&gt;
Available under the &lt;span class="o"&gt;[&lt;/span&gt;MIT license]&lt;span class="o"&gt;(&lt;/span&gt;LICENSE.md&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Switching to the &lt;del&gt;master&lt;/del&gt; main branch
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;g switch-main&lt;/code&gt; (with an alias of &lt;code&gt;g sw-m&lt;/code&gt;) command helps you to change the current branch to the &lt;code&gt;main&lt;/code&gt; branch.&lt;/p&gt;

&lt;p&gt;In case of needing to change the default branch, you can specify it in the &lt;strong&gt;git config&lt;/strong&gt; with the &lt;a href="https://git-scm.com/docs/git-config#Documentation/git-config.txt-initdefaultBranch" rel="noopener noreferrer"&gt;&lt;code&gt;init.defaultBranch&lt;/code&gt; variable&lt;/a&gt; - this added to &lt;strong&gt;git&lt;/strong&gt; very recently and &lt;code&gt;g switch-main&lt;/code&gt; uses it to line up with the standard usage of &lt;strong&gt;git&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example to change the default branch locally&lt;/strong&gt;:&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="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;my-project
&lt;span class="nv"&gt;$ &lt;/span&gt;git config &lt;span class="nt"&gt;--local&lt;/span&gt; branch.default gh-pages
&lt;span class="nv"&gt;$ &lt;/span&gt;git switch &lt;span class="nt"&gt;--create&lt;/span&gt; fix/footer-visibility
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="c"&gt;# work and commit&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;g switch-main
&lt;span class="nv"&gt;$ &lt;/span&gt;g &lt;span class="c"&gt;# invoking git status&lt;/span&gt;
On branch gh-pages
Your branch is up-to-date with &lt;span class="s1"&gt;'origin/gh-pages'&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt;

nothing to commit, working tree clean
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Closing thoughts
&lt;/h1&gt;

&lt;p&gt;If you made it this far thank you for reading my article, and I hope you find some of these features useful.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Have a nice day!&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>git</category>
      <category>cli</category>
      <category>zsh</category>
    </item>
    <item>
      <title>IntelliJ style line duplication in Visual Studio Code</title>
      <dc:creator>Attila Gonda</dc:creator>
      <pubDate>Fri, 08 Nov 2019 21:33:42 +0000</pubDate>
      <link>https://dev.to/pcdevil/intellij-style-line-duplication-in-visual-studio-code-118o</link>
      <guid>https://dev.to/pcdevil/intellij-style-line-duplication-in-visual-studio-code-118o</guid>
      <description>&lt;p&gt;Whenever I can, I use VSCode in favour of IntelliJ. It's more lightweight for my needs and more pleasing UX-wise as well.&lt;/p&gt;

&lt;p&gt;But until now I really missed one thing from IDEA: the line/highlight duplication mechanism.&lt;/p&gt;

&lt;p&gt;In IDEA there are two ways to duplicate code:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Put the cursor somewhere and hit &lt;code&gt;Ctrl + D&lt;/code&gt;. This will duplicate to down the active line&lt;/li&gt;
&lt;li&gt;Select a text and hit &lt;code&gt;Ctrl + D&lt;/code&gt;. This will duplicate to right the selection&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;VSCode didn't have the second method but &lt;a href="https://code.visualstudio.com/updates/v1_40#_duplicate-selection"&gt;just until now&lt;/a&gt;!&lt;/p&gt;

&lt;p&gt;Now you can create keyboard binding with &lt;code&gt;editor.action.duplicateSelection&lt;/code&gt; action, and after adjusting some conditions it acts like the IntelliJ.&lt;/p&gt;

&lt;p&gt;See the following &lt;code&gt;keybindings.json&lt;/code&gt; file snippet:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;

  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"key"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ctrl+d"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"command"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"editor.action.copyLinesDownAction"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"when"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"editorTextFocus &amp;amp;&amp;amp; !editorReadonly &amp;amp;&amp;amp; !editorHasSelection"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"key"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ctrl+d"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"command"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"editor.action.duplicateSelection"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"when"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"editorTextFocus &amp;amp;&amp;amp; !editorReadonly &amp;amp;&amp;amp; editorHasSelection"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;

  &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt; 
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;As you can see there only difference between the &lt;code&gt;when&lt;/code&gt; properties is a negation before &lt;code&gt;editorHasSelection&lt;/code&gt; - if there is no text selected, work as previously, but if there is one, just copy the selection.&lt;/p&gt;

&lt;p&gt;Because I switch between IDEA and Code regularly I often hit the combination in the wrong editor, but from now on, this will work as intended everywhere!&lt;/p&gt;

&lt;p&gt;🎉&lt;/p&gt;

</description>
      <category>vscode</category>
      <category>intellij</category>
      <category>editor</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Indent (xml like) text with flatMap!</title>
      <dc:creator>Attila Gonda</dc:creator>
      <pubDate>Tue, 20 Aug 2019 17:15:45 +0000</pubDate>
      <link>https://dev.to/pcdevil/indent-xml-like-text-with-flatmap-47d6</link>
      <guid>https://dev.to/pcdevil/indent-xml-like-text-with-flatmap-47d6</guid>
      <description>&lt;p&gt;For a hobby-project I needed to indent an XML text which my code compiled and came up with a solution which is quite simple.&lt;/p&gt;

&lt;p&gt;The input is an array with XML tags and all children nodes is nested inside other array.&lt;/p&gt;

&lt;p&gt;A short example for that:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;input&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;&amp;lt;html lang="en"&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;[&lt;/span&gt;
            &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;&amp;lt;title&amp;gt;Hello, World&amp;lt;/title&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;[&lt;/span&gt;
            &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;&amp;lt;h1&amp;gt;It works!&amp;lt;/h1&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;And the output I wanted to achieve is this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;html&lt;/span&gt; &lt;span class="na"&gt;lang=&lt;/span&gt;&lt;span class="s"&gt;"en"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;Hello, World&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;It works!&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;With the given input, the following code would achieve the goal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;indentText&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isArray&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;flatMap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;indentText&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;node&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="se"&gt;\t&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;output&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;input&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;flatMap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;indentText&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;output&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Walk-through on the callback:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A callback passed to the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/flatMap"&gt;Array.prototype.flatMap&lt;/a&gt; will walk through all the items and expected to return an item or an array for &lt;em&gt;flattening&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;If the passed value is not an array, it just returns it back - because we want to maintain the value.&lt;/li&gt;
&lt;li&gt;If it's an array, it's a whole other story: Because flatMap only works on the first level, the method calls itself recursively through flatMap to resolve the deeper layers.

&lt;ul&gt;
&lt;li&gt;The recursive call makes sure there will be no arrays inside the actual one, just text (assuming the input is correct)&lt;/li&gt;
&lt;li&gt;Mapping the items and adding an indent prefix to them. On the deepest level it will add a single character on each item, which will be accumulated during the recursive call going up the levels&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>flatmap</category>
      <category>javascript</category>
      <category>recursive</category>
    </item>
  </channel>
</rss>
