<?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: Sall</title>
    <description>The latest articles on DEV Community by Sall (@sso).</description>
    <link>https://dev.to/sso</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%2F436840%2Fe95b6f58-1d68-4409-8b0c-587c19a7ed65.gif</url>
      <title>DEV Community: Sall</title>
      <link>https://dev.to/sso</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/sso"/>
    <language>en</language>
    <item>
      <title>✨〰️Feature-rich Syntax Highlighting〰️✨</title>
      <dc:creator>Sall</dc:creator>
      <pubDate>Sat, 04 Jun 2022 08:24:46 +0000</pubDate>
      <link>https://dev.to/sso/feature-rich-syntax-highlighting-4k86</link>
      <guid>https://dev.to/sso/feature-rich-syntax-highlighting-4k86</guid>
      <description>&lt;h1&gt;
  &lt;a href="https://github.com/z-shell/zi"&gt;
  &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--qLGRgo7S--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://raw.githubusercontent.com/z-shell/zi/main/docs/images/logo.png" alt="Logo" width="128" height="128"&gt;&lt;/a&gt;
&lt;/h1&gt;




&lt;ul&gt;
&lt;li&gt;&lt;a href="https://z.digitalclouds.dev"&gt;https://z.digitalclouds.dev&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/z-shell"&gt;https://github.com/z-shell&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/z-shell/F-Sy-H"&gt;https://github.com/z-shell/F-Sy-H&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h4&gt;
  
  
  Fast-Syntax-Highlighting Themes
&lt;/h4&gt;


&lt;div class="ltag_asciinema"&gt;
  
&lt;/div&gt;





&lt;h4&gt;
  
  
  Recursive fast-syntax-highlighting, highlights code passed to sh -c
&lt;/h4&gt;


&lt;div class="ltag_asciinema"&gt;
  
&lt;/div&gt;





&lt;p&gt;Switch themes via &lt;code&gt;fast-theme {theme-name}&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--l4E_aObo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://github.com/z-shell/F-Sy-H/raw/main/docs/images/theme.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--l4E_aObo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://github.com/z-shell/F-Sy-H/raw/main/docs/images/theme.png" alt="image1" width="747" height="315"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Run &lt;code&gt;fast-theme -t {theme-name}&lt;/code&gt; option to obtain the snippet above.&lt;/p&gt;

&lt;p&gt;Run &lt;code&gt;fast-theme -l&lt;/code&gt; to list available themes.&lt;/p&gt;




&lt;h3&gt;
  
  
  Variables
&lt;/h3&gt;

&lt;p&gt;Comparing to the project &lt;code&gt;zsh-users/zsh-syntax-highlighting&lt;/code&gt; (the upper line):&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--5Ifrqx8R--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://github.com/z-shell/F-Sy-H/raw/main/docs/images/parameter.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--5Ifrqx8R--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://github.com/z-shell/F-Sy-H/raw/main/docs/images/parameter.png" alt="image could not be loaded" width="140" height="52"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--V91fLHTm--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://github.com/z-shell/F-Sy-H/raw/main/docs/images/in_string.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--V91fLHTm--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://github.com/z-shell/F-Sy-H/raw/main/docs/images/in_string.png" alt="image could not be loaded" width="370" height="52"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  Brackets
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ZpyXXrgp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://github.com/z-shell/F-Sy-H/raw/main/docs/images/brackets.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ZpyXXrgp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://github.com/z-shell/F-Sy-H/raw/main/docs/images/brackets.gif" alt="image could not be loaded" width="660" height="82"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  Conditions
&lt;/h3&gt;

&lt;p&gt;Comparing to the project &lt;code&gt;zsh-users/zsh-syntax-highlighting&lt;/code&gt; (the upper line):&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--F0Mw-ctB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://github.com/z-shell/F-Sy-H/raw/main/docs/images/cplx_cond.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--F0Mw-ctB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://github.com/z-shell/F-Sy-H/raw/main/docs/images/cplx_cond.png" alt="image could not be loaded" width="250" height="52"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  Strings
&lt;/h3&gt;

&lt;p&gt;Exact highlighting that recognizes quotings.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Wse3rVXf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://github.com/z-shell/F-Sy-H/raw/main/docs/images/ideal-string.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Wse3rVXf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://github.com/z-shell/F-Sy-H/raw/main/docs/images/ideal-string.png" alt="image could not be loaded" width="800" height="37"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  here-strings
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--sNRTe-mi--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://github.com/z-shell/F-Sy-H/raw/main/docs/images/herestring.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--sNRTe-mi--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://github.com/z-shell/F-Sy-H/raw/main/docs/images/herestring.png" alt="image could not be loaded" width="600" height="33"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  &lt;code&gt;exec&lt;/code&gt; descriptor-variables
&lt;/h3&gt;

&lt;p&gt;Comparing to the project &lt;code&gt;zsh-users/zsh-syntax-highlighting&lt;/code&gt; (the upper line):&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--3En8qsB5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://github.com/z-shell/F-Sy-H/raw/main/docs/images/execfd_cmp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--3En8qsB5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://github.com/z-shell/F-Sy-H/raw/main/docs/images/execfd_cmp.png" alt="image could not be loaded" width="223" height="56"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  for-loops and alternate syntax (brace &lt;code&gt;{&lt;/code&gt;/&lt;code&gt;}&lt;/code&gt; blocks)
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--6cs2b56Z--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://github.com/z-shell/F-Sy-H/raw/main/docs/images/for-loop-cmp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--6cs2b56Z--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://github.com/z-shell/F-Sy-H/raw/main/docs/images/for-loop-cmp.png" alt="image could not be loaded" width="460" height="63"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  Function definitions
&lt;/h3&gt;

&lt;p&gt;Comparing to the project &lt;code&gt;zsh-users/zsh-syntax-highlighting&lt;/code&gt; (the upper 2 lines):&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--9HJBuLYG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://github.com/z-shell/F-Sy-H/raw/main/docs/images/function.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--9HJBuLYG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://github.com/z-shell/F-Sy-H/raw/main/docs/images/function.png" alt="image could not be loaded" width="338" height="88"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  Recursive &lt;code&gt;eval&lt;/code&gt; and &lt;code&gt;$( )&lt;/code&gt; highlighting
&lt;/h3&gt;

&lt;p&gt;Comparing to the project &lt;code&gt;zsh-users/zsh-syntax-highlighting&lt;/code&gt; (the upper line):&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--4lk-dqqQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://github.com/z-shell/F-Sy-H/raw/main/docs/images/eval_cmp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--4lk-dqqQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://github.com/z-shell/F-Sy-H/raw/main/docs/images/eval_cmp.png" alt="image could not be loaded" width="518" height="49"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  Chroma functions
&lt;/h3&gt;

&lt;p&gt;Highlighting that is specific for a given command.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--nTnoJYJS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://github.com/z-shell/F-Sy-H/raw/main/docs/images/git_chroma.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--nTnoJYJS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://github.com/z-shell/F-Sy-H/raw/main/docs/images/git_chroma.png" alt="image could not be loaded" width="800" height="40"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://github.com/z-shell/F-Sy-H/tree/main/%E2%86%92chroma"&gt;chromas&lt;/a&gt; that are enabled by default can be found &lt;a href="https://github.com/z-shell/F-Sy-H/blob/main/fast-highlight#L172"&gt;here&lt;/a&gt;.&lt;/p&gt;




&lt;h3&gt;
  
  
  Math-mode highlighting
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--sjOWAQ8j--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://github.com/z-shell/F-Sy-H/raw/main/docs/images/math.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--sjOWAQ8j--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://github.com/z-shell/F-Sy-H/raw/main/docs/images/math.gif" alt="image could not be loaded" width="660" height="82"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  Zcalc highlighting
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Sj--317x--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://github.com/z-shell/F-Sy-H/raw/main/docs/images/zcalc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Sj--317x--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://github.com/z-shell/F-Sy-H/raw/main/docs/images/zcalc.png" alt="image could not be loaded" width="508" height="51"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Performance
&lt;/h2&gt;

&lt;p&gt;Performance differences can be observed in this Asciinema recording, where a &lt;code&gt;10 kB&lt;/code&gt; function is being edited.&lt;/p&gt;


&lt;div class="ltag_asciinema"&gt;
  
&lt;/div&gt;





&lt;h2&gt;
  
  
  Installation
&lt;/h2&gt;

&lt;p&gt;Post install try: &lt;code&gt;fast-theme -t z-shell&lt;/code&gt;. To enable: &lt;code&gt;fast-theme z-shell&lt;/code&gt;.&lt;/p&gt;




&lt;h3&gt;
  
  
  Manual
&lt;/h3&gt;

&lt;p&gt;Clone the Repository.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/z-shell/F-Sy-H ~/path/to/fsh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And add the following to your &lt;code&gt;zshrc&lt;/code&gt; file.&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="nb"&gt;source&lt;/span&gt; ~/path/to/fsh/F-Sy-H.plugin.zsh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  &lt;a href="https://github.com/z-shell/zi"&gt;ZI&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Add the following to your &lt;code&gt;zshrc&lt;/code&gt; file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;zi light z-shell/F-Sy-H
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here's an example of how to load the plugin together with a few other popular ones with the use of &lt;a href="https://z.digitalclouds.dev/docs/getting_started/overview/#turbo-mode-zsh--53"&gt;Turbo mode&lt;/a&gt;, i.e.: speeding up the Zsh startup by loading the plugin right after the first prompt, in background:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;zi &lt;span class="nb"&gt;wait &lt;/span&gt;lucid &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
 atinit&lt;span class="s2"&gt;"ZI[COMPINIT_OPTS]=-C; zicompinit; zicdreplay"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    z-shell/F-Sy-H &lt;span class="se"&gt;\&lt;/span&gt;
 blockf &lt;span class="se"&gt;\&lt;/span&gt;
    zsh-users/zsh-completions &lt;span class="se"&gt;\&lt;/span&gt;
 atload&lt;span class="s2"&gt;"!_zsh_autosuggest_start"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    zsh-users/zsh-autosuggestions
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>zsh</category>
      <category>shell</category>
      <category>devops</category>
      <category>tooling</category>
    </item>
    <item>
      <title>✨〰️A Swiss Army Knife for Zsh〰️Unix Shell〰️✨</title>
      <dc:creator>Sall</dc:creator>
      <pubDate>Tue, 31 May 2022 07:54:58 +0000</pubDate>
      <link>https://dev.to/sso/a-swiss-army-knife-for-zshunix-shell-3lgd</link>
      <guid>https://dev.to/sso/a-swiss-army-knife-for-zshunix-shell-3lgd</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--VMI1PAz6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/320/0%2AF1sSKWya8axf3KIY.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--VMI1PAz6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/320/0%2AF1sSKWya8axf3KIY.png" alt="ZI Swiss army knife" width="320" height="320"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  &lt;a href="https://github.com/z-shell/zi"&gt;❮ ZI ❯&lt;/a&gt;  🧙‍‍♀️ A Swiss Army Knife for Zsh.
&lt;/h3&gt;

&lt;p&gt;Designed to glue everything together. 🔗&lt;/p&gt;




&lt;p&gt;&lt;a href="https://z.digitalclouds.dev"&gt;https://z.digitalclouds.dev&lt;/a&gt; | &lt;a href="https://github.com/z-shell/"&gt;GitHub&lt;/a&gt; | &lt;a href="https://github.com/orgs/z-shell/discussions/"&gt;Discussions&lt;/a&gt; | &lt;a href="https://crowdin.digitalclouds.dev"&gt;Localize&lt;/a&gt;&lt;/p&gt;





&lt;div class="ltag_asciinema"&gt;
  
&lt;/div&gt;





&lt;h2&gt;
  
  
  ⚡️ Fast and feature-rich
&lt;/h2&gt;




&lt;p&gt;✴️ &lt;a href="https://z.digitalclouds.dev/search?q=meta+plugins"&gt;🌀Meta-plugins&lt;/a&gt; installs a group of complex plugins via a simple label, curated and optimal settings which are automatically applied.&lt;/p&gt;

&lt;p&gt;✴️ &lt;a href="https://z.digitalclouds.dev/ecosystem/packages"&gt;🌀Packages&lt;/a&gt; offloads from complex configurations and stores them as an easy to swap &amp;amp; share profiles.&lt;/p&gt;

&lt;p&gt;✴️ &lt;a href="https://z.digitalclouds.dev/ecosystem/annexes"&gt;🌀Annexes&lt;/a&gt; are extensions that are installed when required to provide additional functionality, and capabilities.&lt;/p&gt;

&lt;p&gt;✴️ &lt;a href="https://z.digitalclouds.dev/docs/getting_started/overview#turbo-mode-zsh--53"&gt;🌀Turbo&lt;/a&gt; mode yields &lt;strong&gt;50–80%&lt;/strong&gt; faster Zsh startup, just because no one likes to wait for someone :)&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;🥵 Currently biggest issue is that it seems to be too complex for new users and recently made some adjustments which are now starting to provide the results.&lt;/p&gt;
&lt;/blockquote&gt;





&lt;div class="ltag_asciinema"&gt;
  
&lt;/div&gt;





&lt;h2&gt;
  
  
  ☑️ Neat and flexible
&lt;/h2&gt;




&lt;p&gt;✴️ &lt;a href="https://z.digitalclouds.dev/docs/guides/customization#customizing-paths"&gt;Customize&lt;/a&gt; the paths, use &lt;a href="https://z.digitalclouds.dev/docs/guides/customization#multiple-prompts"&gt;multiple prompts&lt;/a&gt; in the same sessions by setting the triggers or create &lt;a href="https://z.digitalclouds.dev/docs/guides/customization#non-github-local-plugins"&gt;your own&lt;/a&gt; plugins to simplify or improve the routine.&lt;/p&gt;

&lt;p&gt;✴️ Supports &lt;a href="https://z.digitalclouds.dev/docs/getting_started/overview#oh-my-zsh-prezto"&gt;Oh My Zsh&lt;/a&gt; and &lt;a href="https://z.digitalclouds.dev/docs/getting_started/overview#oh-my-zsh-prezto"&gt;Prezto&lt;/a&gt; plugins and libraries. ( &lt;a href="https://z.digitalclouds.dev/docs/getting_started/migration"&gt;migration&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;✴️ Does not use &lt;strong&gt;$FPATH&lt;/strong&gt;, loading multiple plugins doesn't clutter &lt;strong&gt;$FPATH&lt;/strong&gt; with the same number of entries, e.g: 10, 15, even, or more.&lt;/p&gt;

&lt;p&gt;✴️ Code is immune to &lt;strong&gt;KSH_ARRAYS&lt;/strong&gt; and other options, which typically cause compatibility problems.&lt;/p&gt;

&lt;p&gt;✴️ Do not require &lt;strong&gt;sudo&lt;/strong&gt;, and provide many ways &amp;amp; workarounds to set up a clean and safe environment. e.g: setting so-called &lt;strong&gt;shims&lt;/strong&gt;  locally.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If there is something that is not supported yet, I am pretty confident that if there will be reasonable demand - it will be implemented. 🔨&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  📈 Familiarize and control
&lt;/h2&gt;




&lt;p&gt;✴️ Quickly familiarize oneself with a new plugin and provides rich and easy-to-digest information that might be helpful on various occasions.&lt;/p&gt;

&lt;p&gt;✴️ &lt;a href="https://z.digitalclouds.dev/docs/guides/commands#loading-and-unloading"&gt;Load, unload&lt;/a&gt; plugins when required, use the ability to &lt;a href="https://z.digitalclouds.dev/docs/guides/commands#completions-management"&gt;manage&lt;/a&gt; completions.&lt;/p&gt;

&lt;p&gt;✴️ Docker &lt;a href="https://github.com/z-shell/playground"&gt;playground&lt;/a&gt; to test, view, or propose configurations. &lt;/p&gt;

&lt;p&gt;✴️ &lt;a href="https://z.digitalclouds.dev/docs/gallery/collection"&gt;💫Gallery&lt;/a&gt;  of the user favorites.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Is only limited to your own 🤦‍♂️ imagination… 🧙‍‍♀️ We need the support to make it better and more approachable to new users, become a 💞 friend of the DEV 💞, and more ☁️ cloud-native ☁️.&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>zi</category>
      <category>shell</category>
      <category>zsh</category>
      <category>devops</category>
    </item>
    <item>
      <title>✨〰️ ZI 〰️✨ Vim Syntax</title>
      <dc:creator>Sall</dc:creator>
      <pubDate>Thu, 28 Apr 2022 08:52:53 +0000</pubDate>
      <link>https://dev.to/sso/-zi-vim-syntax-2d56</link>
      <guid>https://dev.to/sso/-zi-vim-syntax-2d56</guid>
      <description>&lt;p&gt;&lt;a href="https://community.ops.io/images/PxOXrZebj5AbDai_gYqO10eqFupGiKD-zKHMbp4jE4c/w:880/mb:500000/ar:1/aHR0cHM6Ly9jZG4t/aW1hZ2VzLTEubWVk/aXVtLmNvbS9tYXgv/MzIwLzAqRjFzU0tX/eWE4YXhmM0tJWS5w/bmc"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--2QQTbunx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://community.ops.io/images/PxOXrZebj5AbDai_gYqO10eqFupGiKD-zKHMbp4jE4c/w:880/mb:500000/ar:1/aHR0cHM6Ly9jZG4t/aW1hZ2VzLTEubWVk/aXVtLmNvbS9tYXgv/MzIwLzAqRjFzU0tX/eWE4YXhmM0tJWS5w/bmc" alt="ZI Swiss army knife" width="320" height="320"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://github.com/z-shell/zi"&gt;❮ ZI ❯&lt;/a&gt; 🧙‍‍♀️ A Swiss Army Knife for Zsh.
&lt;/h3&gt;

&lt;p&gt;Designed to glue everything together. 🔗&lt;/p&gt;

&lt;p&gt;&lt;a href="https://z.digitalclouds.dev"&gt;https://z.digitalclouds.dev&lt;/a&gt; | &lt;a href="https://github.com/z-shell/"&gt;GitHub&lt;/a&gt; | &lt;a href="https://github.com/orgs/z-shell/discussions/"&gt;Discussions&lt;/a&gt; | &lt;a href="https://crowdin.digitalclouds.dev"&gt;Localize&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A Vim syntax definition for &lt;a href="https://github.com/z-shell/zi"&gt;ZI&lt;/a&gt; commands in any file of type &lt;code&gt;zsh&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  📥 Installation
&lt;/h3&gt;

&lt;p&gt;Load as a Vim plugin. E.g. when using &lt;a href="https://github.com/junegunn/vim-plug"&gt;vim-plug&lt;/a&gt;, add to &lt;code&gt;~/.vimrc&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Plug 'z-shell/zi-vim-syntax'

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and then issue the &lt;code&gt;:PlugInstall&lt;/code&gt; command.&lt;/p&gt;

&lt;h3&gt;
  
  
  📕 Manual Installation
&lt;/h3&gt;

&lt;p&gt;To install the syntax copy the file &lt;code&gt;after/syntax/zsh.vim&lt;/code&gt; under the path &lt;code&gt;~/.vim/syntax/after&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  ✍️ Examples
&lt;/h3&gt;

&lt;p&gt;✴️ The default theme:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--IRICSVGc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://github.com/z-shell/zi-vim-syntax/raw/main/docs/images/default.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--tZMcnbd7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://community.ops.io/images/vd5li16DEj1MTCaZDI7UdxwDW3rjZ0ld1RyYlVOEmq4/w:880/mb:500000/ar:1/aHR0cHM6Ly9yZXMu/Y2xvdWRpbmFyeS5j/b20vcHJhY3RpY2Fs/ZGV2L2ltYWdlL2Zl/dGNoL3MtLUlSSUNT/VkdjLS0vY19saW1p/dCUyQ2ZfYXV0byUy/Q2ZsX3Byb2dyZXNz/aXZlJTJDcV9hdXRv/JTJDd184ODAvaHR0/cHM6Ly9naXRodWIu/Y29tL3otc2hlbGwv/emktdmltLXN5bnRh/eC9yYXcvbWFpbi9k/b2NzL2ltYWdlcy9k/ZWZhdWx0LnBuZw" alt="plastic" width="" height=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;✴️ The theme &lt;code&gt;flrnprz/plastic.vim&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--2w0TeeDx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://github.com/z-shell/zi-vim-syntax/raw/main/docs/images/plastic.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--k7eB5gEU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://community.ops.io/images/YEfbRgRgUjPbYWL6M95qJ2bxa-3sBjw4LUss2vMwyqk/w:880/mb:500000/ar:1/aHR0cHM6Ly9yZXMu/Y2xvdWRpbmFyeS5j/b20vcHJhY3RpY2Fs/ZGV2L2ltYWdlL2Zl/dGNoL3MtLTJ3MFRl/ZUR4LS0vY19saW1p/dCUyQ2ZfYXV0byUy/Q2ZsX3Byb2dyZXNz/aXZlJTJDcV9hdXRv/JTJDd184ODAvaHR0/cHM6Ly9naXRodWIu/Y29tL3otc2hlbGwv/emktdmltLXN5bnRh/eC9yYXcvbWFpbi9k/b2NzL2ltYWdlcy9w/bGFzdGljLnBuZw" alt="plastic" width="" height=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;✴️ The theme &lt;code&gt;slate&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--qqD7txfc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://github.com/z-shell/zi-vim-syntax/raw/main/docs/images/slate.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--dIpsdt20--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://community.ops.io/images/9NJiiJWInB53siC7ry36NxIHq56iKRDREO9onm6vC6w/w:880/mb:500000/ar:1/aHR0cHM6Ly9yZXMu/Y2xvdWRpbmFyeS5j/b20vcHJhY3RpY2Fs/ZGV2L2ltYWdlL2Zl/dGNoL3MtLXFxRDd0/eGZjLS0vY19saW1p/dCUyQ2ZfYXV0byUy/Q2ZsX3Byb2dyZXNz/aXZlJTJDcV9hdXRv/JTJDd184ODAvaHR0/cHM6Ly9naXRodWIu/Y29tL3otc2hlbGwv/emktdmltLXN5bnRh/eC9yYXcvbWFpbi9k/b2NzL2ltYWdlcy9z/bGF0ZS5wbmc" alt="slate" width="" height=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;✴️ The theme &lt;code&gt;murphy&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--kyVpK1A6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://github.com/z-shell/zi-vim-syntax/raw/main/docs/images/murphy.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--cdA5J_Ll--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://community.ops.io/images/LwJ14a3GBXeERUFzDsN8x5ABRgq8fi1Nfy5_Qy4fOZI/w:880/mb:500000/ar:1/aHR0cHM6Ly9yZXMu/Y2xvdWRpbmFyeS5j/b20vcHJhY3RpY2Fs/ZGV2L2ltYWdlL2Zl/dGNoL3MtLWt5VnBL/MUE2LS0vY19saW1p/dCUyQ2ZfYXV0byUy/Q2ZsX3Byb2dyZXNz/aXZlJTJDcV9hdXRv/JTJDd184ODAvaHR0/cHM6Ly9naXRodWIu/Y29tL3otc2hlbGwv/emktdmltLXN5bnRh/eC9yYXcvbWFpbi9k/b2NzL2ltYWdlcy9t/dXJwaHkucG5n" alt="plastic" width="" height=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;✴️ The theme &lt;code&gt;lucasprag/simpleblack&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--7IB1Y0JK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://github.com/z-shell/zi-vim-syntax/raw/main/docs/images/simpleblack.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--s5dPJRwZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://community.ops.io/images/ms5OLq46wuSHGHSmhmjwaSlXYJv9kg3lP-BeplgYej8/w:880/mb:500000/ar:1/aHR0cHM6Ly9yZXMu/Y2xvdWRpbmFyeS5j/b20vcHJhY3RpY2Fs/ZGV2L2ltYWdlL2Zl/dGNoL3MtLTdJQjFZ/MEpLLS0vY19saW1p/dCUyQ2ZfYXV0byUy/Q2ZsX3Byb2dyZXNz/aXZlJTJDcV9hdXRv/JTJDd184ODAvaHR0/cHM6Ly9naXRodWIu/Y29tL3otc2hlbGwv/emktdmltLXN5bnRh/eC9yYXcvbWFpbi9k/b2NzL2ltYWdlcy9z/aW1wbGVibGFjay5w/bmc" alt="plastic" width="" height=""&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>zi</category>
      <category>shell</category>
      <category>zsh</category>
      <category>devops</category>
    </item>
    <item>
      <title>⚙️ ❮ ZSH Native Scripting Handbook ❯</title>
      <dc:creator>Sall</dc:creator>
      <pubDate>Tue, 01 Mar 2022 21:33:52 +0000</pubDate>
      <link>https://dev.to/sso/zsh-native-scripting-handbook-2f74</link>
      <guid>https://dev.to/sso/zsh-native-scripting-handbook-2f74</guid>
      <description>&lt;p&gt;&lt;a href="https://github.com/z-shell/zi"&gt;&lt;br&gt;
  &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--qLGRgo7S--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://raw.githubusercontent.com/z-shell/zi/main/docs/images/logo.png" alt="Logo" width="128" height="128"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;

&lt;/h2&gt;
&lt;p&gt;❮ &lt;a href="https://github.com/z-shell/zi"&gt;ZI&lt;/a&gt; ❯&lt;/p&gt;



&lt;p&gt;&lt;a href="https://z.digitalclouds.dev"&gt;https://z.digitalclouds.dev&lt;/a&gt; | &lt;a href="https://github.com/z-shell"&gt;GitHub&lt;/a&gt; | &lt;a href="https://twitter.com/zshell_zi"&gt;Twitter&lt;/a&gt; | &lt;a href="https://github.com/z-shell/community/issues/new?assignees=&amp;amp;labels=%F0%9F%91%A5+member&amp;amp;template=membership.yml&amp;amp;title=team%3A+"&gt;Join the team&lt;/a&gt;&lt;/p&gt;




&lt;ul&gt;
&lt;li&gt;
Information

&lt;ul&gt;
&lt;li&gt;@ is about keeping array form&lt;/li&gt;
&lt;li&gt;extended_glob&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;
Constructs

&lt;ul&gt;
&lt;li&gt;Reading a file&lt;/li&gt;
&lt;li&gt;Skipping dirname basename&lt;/li&gt;
&lt;li&gt;Resolve Symlinks&lt;/li&gt;
&lt;li&gt;Skipping grep&lt;/li&gt;
&lt;li&gt;Multi-line matching like with grep&lt;/li&gt;
&lt;li&gt;Pattern matching in AND-fashion&lt;/li&gt;
&lt;li&gt;Skipping tr&lt;/li&gt;
&lt;li&gt;Ternary expressions with &lt;code&gt;+,-,:+,:-&lt;/code&gt; substitutions&lt;/li&gt;
&lt;li&gt;Ternary expressions with &lt;code&gt;:#&lt;/code&gt; substitution&lt;/li&gt;
&lt;li&gt;Using built-in regular expressions engine&lt;/li&gt;
&lt;li&gt;Skipping uniq&lt;/li&gt;
&lt;li&gt;Skipping awk&lt;/li&gt;
&lt;li&gt;Searching arrays&lt;/li&gt;
&lt;li&gt;Code execution in &lt;code&gt;//&lt;/code&gt; substitution&lt;/li&gt;
&lt;li&gt;Serializing data&lt;/li&gt;
&lt;li&gt;Tip: serializing with Bash&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;
Real-world examples

&lt;ul&gt;
&lt;li&gt;Testing for Git subcommand&lt;/li&gt;
&lt;li&gt;Counting unquoted-only apostrophes&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;
Tips and Tricks

&lt;ul&gt;
&lt;li&gt;Parsing INI file&lt;/li&gt;
&lt;/ul&gt;


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




&lt;h2&gt;
  
  
  Information
&lt;/h2&gt;




&lt;h3&gt;
  
  
  @ is about keeping array form
&lt;/h3&gt;




&lt;p&gt;How to access all array elements in a shell? The standard answer: &lt;code&gt;use @ subscript&lt;/code&gt;, i.e. &lt;code&gt;${array[@]}&lt;/code&gt;. However, this&lt;br&gt;
is the Bash &amp;amp; Ksh way (and with the option &lt;code&gt;KSH_ARRAYS&lt;/code&gt;, Zsh also works this way, i.e. needs &lt;code&gt;@&lt;/code&gt; to access the whole&lt;br&gt;
array). Z shell &lt;strong&gt;is different&lt;/strong&gt;: it is &lt;code&gt;$array&lt;/code&gt; that refers to all elements anyway. There is no need for the &lt;code&gt;@&lt;/code&gt;&lt;br&gt;
subscript.&lt;/p&gt;

&lt;p&gt;So what use has &lt;code&gt;@&lt;/code&gt; in the Zsh-world? It is: "&lt;code&gt;keep array form&lt;/code&gt;" or "&lt;code&gt;do not join&lt;/code&gt;". When is it activated? When the user&lt;br&gt;
quotes the array, i.e. invokes &lt;code&gt;"$array"&lt;/code&gt;, he induces &lt;em&gt;joining&lt;/em&gt; of all array elements (into a single string). &lt;code&gt;@&lt;/code&gt; is to&lt;br&gt;
have elements still quoted (so empty elements are preserved), but not joined.&lt;/p&gt;

&lt;p&gt;Two forms are available, &lt;code&gt;"$array[@]"&lt;/code&gt; and &lt;code&gt;"${(@)array}"&lt;/code&gt;. The first form has an additional effect – when an option&lt;br&gt;
&lt;code&gt;KSH_ARRAYS&lt;/code&gt; is set, it indeed induces referencing to the whole array instead of a first element only. It should then&lt;br&gt;
use braces, i.e. &lt;code&gt;${array[@]}&lt;/code&gt;, &lt;code&gt;"${array[@]}"&lt;/code&gt; (&lt;code&gt;KSH_ARRAYS&lt;/code&gt; requirement).&lt;/p&gt;

&lt;p&gt;In practice, if you'll use &lt;code&gt;@&lt;/code&gt; as a subscript – &lt;code&gt;[@]&lt;/code&gt;, not as a flag – &lt;code&gt;${(@)...}&lt;/code&gt;, then you'll make the code&lt;br&gt;
&lt;code&gt;KSH_ARRAYS&lt;/code&gt;-compatible.&lt;/p&gt;


&lt;h3&gt;
  
  
  extended_glob
&lt;/h3&gt;



&lt;p&gt;Glob-flags &lt;code&gt;#b&lt;/code&gt; and &lt;code&gt;#m&lt;/code&gt; require &lt;code&gt;setopt extended_glob&lt;/code&gt;. Patterns utilizing &lt;code&gt;~&lt;/code&gt; and &lt;code&gt;^&lt;/code&gt; also require it. Extended-glob&lt;br&gt;
is one of the main features of Zsh.&lt;/p&gt;


&lt;h2&gt;
  
  
  Constructs
&lt;/h2&gt;


&lt;h3&gt;
  
  
  Reading a file
&lt;/h3&gt;




&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;declare&lt;/span&gt; &lt;span class="nt"&gt;-a&lt;/span&gt; lines&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nv"&gt;lines&lt;/span&gt;&lt;span class="o"&gt;=(&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="p"&gt;(@f)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&amp;lt;path/file&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;This preserves empty lines because of double-quoting (the outside one). &lt;code&gt;@&lt;/code&gt;-flag is used to obtain an array instead of a&lt;br&gt;
scalar. If you don't want empty lines preserved, you can also skip &lt;code&gt;@&lt;/code&gt;-splitting, as is explained in the&lt;br&gt;
Information section:&lt;br&gt;
&lt;/p&gt;

&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;declare&lt;/span&gt; &lt;span class="nt"&gt;-a&lt;/span&gt; lines&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nv"&gt;lines&lt;/span&gt;&lt;span class="o"&gt;=(&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="p"&gt;(f)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&amp;lt;path/file&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; &lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;Note: &lt;code&gt;$(&amp;lt;...)&lt;/code&gt; construct strips trailing empty lines.&lt;/p&gt;




&lt;h3&gt;
  
  
  Reading from stdin
&lt;/h3&gt;




&lt;p&gt;This topic is governed by the same principles a the previous paragraph (&lt;code&gt;Reading a file&lt;/code&gt;), with the single difference&lt;br&gt;
that instead of the substitution &lt;code&gt;"$(&amp;lt;file-path)"&lt;/code&gt; the substitution that should be used is &lt;code&gt;"$(command arg1 ...)"&lt;/code&gt;,&lt;br&gt;
i.e.:&lt;br&gt;
&lt;/p&gt;

&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;declare&lt;/span&gt; &lt;span class="nt"&gt;-a&lt;/span&gt; lines&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nv"&gt;lines&lt;/span&gt;&lt;span class="o"&gt;=(&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="p"&gt;(f)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;command &lt;/span&gt;arg1 ...&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; &lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;This will read the &lt;code&gt;command's&lt;/code&gt; output into the array &lt;code&gt;lines&lt;/code&gt;. The version that does &lt;code&gt;@&lt;/code&gt; splitting and retains any empty&lt;br&gt;
lines are:&lt;br&gt;
&lt;/p&gt;

&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;declare&lt;/span&gt; &lt;span class="nt"&gt;-a&lt;/span&gt; lines&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nv"&gt;lines&lt;/span&gt;&lt;span class="o"&gt;=(&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="p"&gt;(f@)&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;command &lt;/span&gt;arg1 ...&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;Note that instead of four double-quotes &lt;code&gt;"&lt;/code&gt;, an idiom that is justified (simply suggested) by the Zsh documentation (and&lt;br&gt;
was used in the previous paragraph, in the snippet &lt;code&gt;... "${(@f)"$(&amp;lt;path/file)"}" ...&lt;/code&gt;), only &lt;strong&gt;two&lt;/strong&gt; double-quotes are&lt;br&gt;
being used. I've investigated this form with the main Zsh developers on the &lt;code&gt;zsh-workers@zsh.org&lt;/code&gt; mailing list and it&lt;br&gt;
was clearly stated that single, outside quoting of &lt;code&gt;${(f@)...}&lt;/code&gt; substitution works as if it was also separately applied&lt;br&gt;
to &lt;code&gt;$(command ...)&lt;/code&gt; (or to &lt;code&gt;$(&amp;lt;file-path)&lt;/code&gt;) inner substitution, so the second double-quoting isn't needed.&lt;/p&gt;


&lt;h3&gt;
  
  
  Skipping dirname basename
&lt;/h3&gt;



&lt;p&gt;&lt;code&gt;dirname&lt;/code&gt; and &lt;code&gt;basename&lt;/code&gt; can be skipped by:&lt;br&gt;
&lt;/p&gt;

&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;local dirname&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;PWD&lt;/span&gt;:h&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nb"&gt;local basename&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;PWD&lt;/span&gt;:t&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;Read more: &lt;a href="http://zsh.sourceforge.net/Doc/Release/Expansion.html#Modifiers"&gt;zsh: 14 Expansion&lt;/a&gt;.&lt;/p&gt;




&lt;h3&gt;
  
  
  Resolve Symlinks
&lt;/h3&gt;




&lt;p&gt;Symbolic links can be turned into an absolute path with:&lt;br&gt;
&lt;/p&gt;

&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;local &lt;/span&gt;&lt;span class="nv"&gt;absolute_path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;PWD&lt;/span&gt;:A&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;






&lt;h3&gt;
  
  
  Skipping grep
&lt;/h3&gt;






&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;declare&lt;/span&gt; &lt;span class="nt"&gt;-a&lt;/span&gt; lines&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nv"&gt;lines&lt;/span&gt;&lt;span class="o"&gt;=(&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="p"&gt;(@f)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&amp;lt;path/file&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;declare&lt;/span&gt; &lt;span class="nt"&gt;-a&lt;/span&gt; grepped&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nv"&gt;grepped&lt;/span&gt;&lt;span class="o"&gt;=(&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="p"&gt;(M)lines&lt;/span&gt;:#&lt;span class="p"&gt;*query*&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; &lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;To have the &lt;code&gt;grep -v&lt;/code&gt; effect, skip the &lt;code&gt;M&lt;/code&gt;-flag. To grep case-insensitively, use &lt;code&gt;\#i&lt;/code&gt; glob flag (&lt;code&gt;...:#(#i)\*query*}&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;As it can be seen, &lt;code&gt;${...:#...}&lt;/code&gt; substitution is filtering of the array, which by default filters-out elements (&lt;code&gt;(M)&lt;/code&gt;&lt;br&gt;
flag induces the opposite behavior). When used with string, not an array, it behaves similarly: returns an empty string&lt;br&gt;
when &lt;code&gt;{input_string_var:#pattern}&lt;/code&gt; matches the whole input string.&lt;/p&gt;

&lt;p&gt;Side-note: &lt;code&gt;(M)&lt;/code&gt; flag can be used also with &lt;code&gt;${(M)var#pattern}&lt;/code&gt; and other substitutions, to retain what's matched by the&lt;br&gt;
pattern instead of removing that.&lt;/p&gt;


&lt;h4&gt;
  
  
  Multi-line matching like with grep
&lt;/h4&gt;



&lt;p&gt;Suppose you have a Subversion repository and want to check if it contains files being not under version control. You&lt;br&gt;
could do this in Bash style like follows:&lt;br&gt;
&lt;/p&gt;

&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;local &lt;/span&gt;&lt;span class="nv"&gt;svn_status&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;svn status&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$svn_status&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; | &lt;span class="se"&gt;\g&lt;/span&gt;rep &lt;span class="se"&gt;\^\?&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
    &lt;/span&gt;&lt;span class="nb"&gt;echo &lt;/span&gt;found
&lt;span class="k"&gt;fi&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;Those are 3 forks: for &lt;code&gt;svn status&lt;/code&gt;, for &lt;code&gt;echo&lt;/code&gt;, and for &lt;code&gt;grep&lt;/code&gt;. This can be solved by the &lt;code&gt;:#&lt;/code&gt; substitution and &lt;code&gt;(M)&lt;/code&gt;&lt;br&gt;
flag described above in this section (just check if the number of matched lines is greater than 0). However, there's a&lt;br&gt;
more direct approach:&lt;br&gt;
&lt;/p&gt;

&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;local &lt;/span&gt;&lt;span class="nv"&gt;svn_status&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;svn status&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nb"&gt;nl&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;$'&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s1"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$svn_status&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt;&lt;span class="o"&gt;((&lt;/span&gt;&lt;span class="c"&gt;#s)|$nl)\?* ]]; then&lt;/span&gt;
  &lt;span class="nb"&gt;echo &lt;/span&gt;found
&lt;span class="k"&gt;fi&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;This requires &lt;code&gt;extendedglob&lt;/code&gt;. The &lt;code&gt;(#s)&lt;/code&gt; means: "start of the string". So &lt;code&gt;((#s)|$nl)&lt;/code&gt; means "start of the string OR&lt;br&gt;
preceded by a new-line".&lt;/p&gt;

&lt;p&gt;If the &lt;code&gt;extendedglob&lt;/code&gt; option cannot be used for some reason, this can be achieved also without it, but essentially it&lt;br&gt;
means that alternative (i.e. &lt;code&gt;|&lt;/code&gt;) of two versions of the pattern will have to be matched:&lt;br&gt;
&lt;/p&gt;

&lt;pre class="highlight shell"&gt;&lt;code&gt;setopt localoptions noextendedglob
&lt;span class="nb"&gt;local &lt;/span&gt;&lt;span class="nv"&gt;svn_status&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;svn status&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nb"&gt;nl&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;$'&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s1"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$svn_status&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="se"&gt;\?&lt;/span&gt;&lt;span class="k"&gt;*&lt;/span&gt;|&lt;span class="k"&gt;*&lt;/span&gt;&lt;span class="nv"&gt;$nl&lt;/span&gt;&lt;span class="se"&gt;\?&lt;/span&gt;&lt;span class="k"&gt;*&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
  &lt;/span&gt;&lt;span class="nb"&gt;echo &lt;/span&gt;found
&lt;span class="k"&gt;fi&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;In general, multi-line matching falls into the following idiom (&lt;code&gt;extended glob&lt;/code&gt; version):&lt;br&gt;
&lt;/p&gt;

&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;local &lt;/span&gt;&lt;span class="nv"&gt;needle&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"?"&lt;/span&gt; &lt;span class="nv"&gt;required_preceding&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'[[:space:]]#'&lt;/span&gt;
&lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;svn status&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt;&lt;span class="o"&gt;((&lt;/span&gt;&lt;span class="c"&gt;#s)|$nl)${~required_preceding}${needle}* ]] &amp;amp;&amp;amp; echo found&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;It does a single fork (calls &lt;code&gt;svn&lt;/code&gt; status). The &lt;code&gt;${~variable}&lt;/code&gt; means (the&lt;code&gt;~&lt;/code&gt; init): "the variable is holding a pattern,&lt;br&gt;
interpret it". All in all, instead of regular expressions we were using patterns (globs) (see&lt;br&gt;
this section).&lt;/p&gt;


&lt;h3&gt;
  
  
  Pattern matching in AND-fashion
&lt;/h3&gt;




&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="s2"&gt;"abc xyz efg"&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt;abc&lt;span class="k"&gt;*&lt;/span&gt;~^&lt;span class="k"&gt;*&lt;/span&gt;efg&lt;span class="k"&gt;*&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; print Match found
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;The &lt;code&gt;~&lt;/code&gt; is a negation -- &lt;code&gt;match \*abc* but not ...&lt;/code&gt;. Then, &lt;code&gt;^&lt;/code&gt; is also a negation. The effect is:&lt;br&gt;
&lt;code&gt;\*ABC* but not those that don't have \*efg*&lt;/code&gt; which equals to: &lt;code&gt;\*ABC* but those that have also \*efg*&lt;/code&gt;. This is a&lt;br&gt;
regular pattern and it can be used with &lt;code&gt;:#&lt;/code&gt; above to search arrays, or with the &lt;code&gt;R&lt;/code&gt;-subscript flag to search hashes&lt;br&gt;
(&lt;code&gt;${hsh[\(R)\*pattern*]}&lt;/code&gt;), etc. The inventor of those patterns is Mikael Magnusson.&lt;/p&gt;


&lt;h3&gt;
  
  
  Skipping tr
&lt;/h3&gt;




&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;declare&lt;/span&gt; &lt;span class="nt"&gt;-A&lt;/span&gt; map&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nv"&gt;map&lt;/span&gt;&lt;span class="o"&gt;=(&lt;/span&gt; a 1 b 2 &lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nv"&gt;text&lt;/span&gt;&lt;span class="o"&gt;=(&lt;/span&gt; &lt;span class="s2"&gt;"ab"&lt;/span&gt; &lt;span class="s2"&gt;"ba"&lt;/span&gt; &lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="nv"&gt;text&lt;/span&gt;&lt;span class="o"&gt;=(&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;text&lt;/span&gt;&lt;span class="p"&gt;[@]//(#m)?/&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;$MATCH&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="k"&gt;}}&lt;/span&gt; &lt;span class="o"&gt;)&lt;/span&gt;
print &lt;span class="nv"&gt;$text&lt;/span&gt; ▶ 12 21
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;&lt;code&gt;#m&lt;/code&gt; flag enables the &lt;code&gt;$MATCH&lt;/code&gt; parameter. At each &lt;code&gt;//&lt;/code&gt; substitution, &lt;code&gt;$map&lt;/code&gt; is queried for character-replacement. You&lt;br&gt;
can substitute a text variable too, just skip &lt;code&gt;[@]&lt;/code&gt; and parentheses in the assignment.&lt;/p&gt;


&lt;h3&gt;
  
  
  Ternary expressions with &lt;code&gt;+,-,:+,:-&lt;/code&gt; substitutions
&lt;/h3&gt;




&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;HELP&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"yes"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; print &lt;span class="k"&gt;${${&lt;/span&gt;&lt;span class="nv"&gt;HELP&lt;/span&gt;:+help&lt;span class="p"&gt; enabled&lt;/span&gt;&lt;span class="k"&gt;}:-&lt;/span&gt;&lt;span class="nv"&gt;help&lt;/span&gt;&lt;span class="p"&gt; disabled&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; ▶ &lt;span class="nb"&gt;help &lt;/span&gt;enabled
&lt;span class="nv"&gt;HELP&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;""&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; print &lt;span class="k"&gt;${${&lt;/span&gt;&lt;span class="nv"&gt;HELP&lt;/span&gt;:+help&lt;span class="p"&gt; enabled&lt;/span&gt;&lt;span class="k"&gt;}:-&lt;/span&gt;&lt;span class="nv"&gt;help&lt;/span&gt;&lt;span class="p"&gt; disabled&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; ▶ &lt;span class="nb"&gt;help &lt;/span&gt;disabled
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;Ternary expression is known from &lt;code&gt;C&lt;/code&gt; language but exists also in Zsh, but directly only in a math context, i.e.&lt;br&gt;
&lt;code&gt;\(( a = a &amp;gt; 0 ? b : c ))&lt;/code&gt;. The flexibility of Zsh allows such expressions also in a normal context. Above is an&lt;br&gt;
example. &lt;code&gt;:+&lt;/code&gt; is "if not empty, substitute …" &lt;code&gt;:-&lt;/code&gt; is "if empty, substitute …". You can save a great number of lines of&lt;br&gt;
code with those substitutions, it's normally at least 4-lines &lt;code&gt;if&lt;/code&gt; condition or lengthy &lt;code&gt;&amp;amp;&amp;amp;&lt;/code&gt;/&lt;code&gt;||&lt;/code&gt; use.&lt;/p&gt;


&lt;h3&gt;
  
  
  Ternary expressions with &lt;code&gt;:#&lt;/code&gt; substitution
&lt;/h3&gt;




&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;var&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;abc&lt;span class="p"&gt;;&lt;/span&gt; print &lt;span class="k"&gt;${${${&lt;/span&gt;&lt;span class="p"&gt;(M)var&lt;/span&gt;:#abc&lt;span class="k"&gt;}&lt;/span&gt;:+is&lt;span class="p"&gt; abc&lt;/span&gt;&lt;span class="k"&gt;}:-&lt;/span&gt;&lt;span class="nv"&gt;not&lt;/span&gt;&lt;span class="p"&gt; abc&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; ▶ is abc
&lt;span class="nv"&gt;var&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;abcd&lt;span class="p"&gt;;&lt;/span&gt; print &lt;span class="k"&gt;${${${&lt;/span&gt;&lt;span class="p"&gt;(M)var&lt;/span&gt;:#abc&lt;span class="k"&gt;}&lt;/span&gt;:+is&lt;span class="p"&gt; abc&lt;/span&gt;&lt;span class="k"&gt;}:-&lt;/span&gt;&lt;span class="nv"&gt;not&lt;/span&gt;&lt;span class="p"&gt; abc&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; ▶ not abc
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;A one-line "if var = x, then …, else …". Again, can spare a great amount of boring code that makes a 10-line function a&lt;br&gt;
20-line one.&lt;/p&gt;

&lt;p&gt;[#built-in-regular-expressions-engine]&lt;/p&gt;


&lt;h3&gt;
  
  
  Using built-in regular expressions engine
&lt;/h3&gt;




&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="s2"&gt;"aabbb"&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="c"&gt;#b)(a##)*(b(#c2,2)) ]] &amp;amp;&amp;amp; print ${match[1]}-${match[2]} ▶ aa-bb&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;&lt;code&gt;\##&lt;/code&gt; is: "1 or more". &lt;code&gt;(#c2,2)&lt;/code&gt; is: "exactly 2". A few other constructs: &lt;code&gt;#&lt;/code&gt; is "0 or more", &lt;code&gt;?&lt;/code&gt; is "any character",&lt;br&gt;
&lt;code&gt;(a|b|)&lt;/code&gt; is "a or b or empty match". &lt;code&gt;#b&lt;/code&gt; enables the &lt;code&gt;$match&lt;/code&gt; parameters. There's also &lt;code&gt;#m&lt;/code&gt; but it has one parameter&lt;br&gt;
&lt;code&gt;$MATCH&lt;/code&gt; for whole matched text, not for any parenthesis.&lt;/p&gt;

&lt;p&gt;Zsh patterns are a custom regular expressions engine. They are slightly faster than the &lt;code&gt;zsh/regex&lt;/code&gt; module (used for&lt;br&gt;
&lt;code&gt;=~&lt;/code&gt; operator) and don't have that dependency (regex module can be not present, e.g. in default static build of Zsh).&lt;br&gt;
Also, they can be used in substitutions, for example in &lt;code&gt;//&lt;/code&gt; substitution.&lt;/p&gt;


&lt;h3&gt;
  
  
  Skipping uniq
&lt;/h3&gt;




&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;declare&lt;/span&gt; &lt;span class="nt"&gt;-aU&lt;/span&gt; array&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nv"&gt;array&lt;/span&gt;&lt;span class="o"&gt;=(&lt;/span&gt; a a b &lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; print &lt;span class="nv"&gt;$array&lt;/span&gt; ▶ a b
&lt;span class="nb"&gt;declare&lt;/span&gt; &lt;span class="nt"&gt;-a&lt;/span&gt; array&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nv"&gt;array&lt;/span&gt;&lt;span class="o"&gt;=(&lt;/span&gt; a a b &lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; print &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="p"&gt;(u)array&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; ▶ a b
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;Enable &lt;code&gt;-U&lt;/code&gt; flag for array so that it guards elements to be unique, or use &lt;code&gt;u&lt;/code&gt;-flag to make unique elements of an array.&lt;/p&gt;


&lt;h3&gt;
  
  
  Skipping awk
&lt;/h3&gt;




&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;declare&lt;/span&gt; &lt;span class="nt"&gt;-a&lt;/span&gt; list&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nv"&gt;list&lt;/span&gt;&lt;span class="o"&gt;=(&lt;/span&gt; &lt;span class="s2"&gt;"a,b,c,1,e"&lt;/span&gt; &lt;span class="s2"&gt;"p,q,r,2,t"&lt;/span&gt; &lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
print &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;list&lt;/span&gt;&lt;span class="p"&gt;[@]/(#b)([^,]##,)(#c3,3)([^,]##)*/&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;match&lt;/span&gt;&lt;span class="p"&gt;[2]&lt;/span&gt;&lt;span class="k"&gt;}}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; ▶ 1 2
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;The pattern specifies 3 blocks of &lt;code&gt;[^,]##,&lt;/code&gt; so 3 "not-comma multiple times, then comma", then the single block of&lt;br&gt;
"not-comma multiple times" in second parentheses -- and then replaces this with second parentheses. The result is the&lt;br&gt;
4th column extracted from multiple lines of text, something &lt;code&gt;awk&lt;/code&gt; is often used for. Another method is the use of the&lt;br&gt;
&lt;code&gt;s&lt;/code&gt;-flag. For a single line of text:&lt;br&gt;
&lt;/p&gt;

&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;text&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"a,b,c,1,e"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; print &lt;span class="k"&gt;${${&lt;/span&gt;&lt;span class="p"&gt;(s&lt;/span&gt;:,:&lt;span class="p"&gt;)text&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="p"&gt;[4]&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; ▶ 1
&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;Thanks to in-substitution code-execution capabilities it's possible to use &lt;code&gt;s&lt;/code&gt;-flag to apply it to multiple lines:&lt;br&gt;
&lt;/p&gt;

&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;declare&lt;/span&gt; &lt;span class="nt"&gt;-a&lt;/span&gt; list&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nv"&gt;list&lt;/span&gt;&lt;span class="o"&gt;=(&lt;/span&gt; &lt;span class="s2"&gt;"a,b,c,1,e"&lt;/span&gt; &lt;span class="s2"&gt;"p,q,r,2,t"&lt;/span&gt; &lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
print &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;list&lt;/span&gt;&lt;span class="p"&gt;[@]/(#m)*/&lt;/span&gt;&lt;span class="k"&gt;${${&lt;/span&gt;&lt;span class="p"&gt;(s&lt;/span&gt;:,:&lt;span class="p"&gt;)MATCH&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="p"&gt;[4]&lt;/span&gt;&lt;span class="k"&gt;}}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; ▶ 1 2
&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;There is a problem with the &lt;code&gt;(s::)&lt;/code&gt; flag that can be solved if Zsh is version &lt;code&gt;5.4&lt;/code&gt; or higher: if there will be single&lt;br&gt;
input column, e.g. &lt;code&gt;list=( "column1" "a,b")&lt;/code&gt; instead of two or more columns (i.e. &lt;code&gt;list=( "column1,column2" "a,b" )&lt;/code&gt;),&lt;br&gt;
then &lt;code&gt;(s::)&lt;/code&gt; will return &lt;strong&gt;string&lt;/strong&gt; instead of 1-element &lt;strong&gt;array&lt;/strong&gt;. So the index &lt;code&gt;[4]&lt;/code&gt; in the above snippet will index a&lt;br&gt;
string, and show its 4-th letter. Starting with Zsh 5.4, thanks to a patch by Bart Schaefer&lt;br&gt;
(&lt;code&gt;40640: the (A) parameter flag forces array result even if...&lt;/code&gt;), it is possible to force &lt;strong&gt;array&lt;/strong&gt;-kind of result even&lt;br&gt;
for a single column, by adding &lt;code&gt;(A)&lt;/code&gt; flag, i.e.:&lt;br&gt;
&lt;/p&gt;

&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;declare&lt;/span&gt; &lt;span class="nt"&gt;-a&lt;/span&gt; list&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nv"&gt;list&lt;/span&gt;&lt;span class="o"&gt;=(&lt;/span&gt; &lt;span class="s2"&gt;"a,b,c,1,e"&lt;/span&gt; &lt;span class="s2"&gt;"p,q,r,2,t"&lt;/span&gt; &lt;span class="s2"&gt;"column1"&lt;/span&gt; &lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
print &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;list&lt;/span&gt;&lt;span class="p"&gt;[@]/(#m)*/&lt;/span&gt;&lt;span class="k"&gt;${${&lt;/span&gt;&lt;span class="p"&gt;(As&lt;/span&gt;:,:&lt;span class="p"&gt;)MATCH&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="p"&gt;[4]&lt;/span&gt;&lt;span class="k"&gt;}}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; ▶ 1 2
print &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;list&lt;/span&gt;&lt;span class="p"&gt;[@]/(#m)*/&lt;/span&gt;&lt;span class="k"&gt;${${&lt;/span&gt;&lt;span class="p"&gt;(s&lt;/span&gt;:,:&lt;span class="p"&gt;)MATCH&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="p"&gt;[4]&lt;/span&gt;&lt;span class="k"&gt;}}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; ▶ 1 2 u
&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;Side-note: &lt;code&gt;(A)&lt;/code&gt; flag is often used together with &lt;code&gt;::=&lt;/code&gt; assignment-substitution and &lt;code&gt;(P)&lt;/code&gt; flag, to assign arrays and&lt;br&gt;
hashes by-name.&lt;/p&gt;


&lt;h3&gt;
  
  
  Searching arrays
&lt;/h3&gt;




&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;declare&lt;/span&gt; &lt;span class="nt"&gt;-a&lt;/span&gt; array&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nv"&gt;array&lt;/span&gt;&lt;span class="o"&gt;=(&lt;/span&gt; a b &lt;span class="s2"&gt;" c1"&lt;/span&gt; d &lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; print &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;array&lt;/span&gt;&lt;span class="p"&gt;[(r)[[&lt;/span&gt;:space:]][[:alpha:]]&lt;span class="p"&gt;*]&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; ▶ c1
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;&lt;code&gt;\[[:space:]]&lt;/code&gt; contains unicode spaces. This is often used in conditional expression like &lt;code&gt;[[ -z ${array[(r)...]} ]]&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Note that Skipping grep that uses &lt;code&gt;:#&lt;/code&gt; substitution can also be used to search arrays.&lt;/p&gt;


&lt;h3&gt;
  
  
  Code execution in &lt;code&gt;//&lt;/code&gt; substitution
&lt;/h3&gt;




&lt;pre class="highlight shell"&gt;&lt;code&gt;append&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; gathered+&lt;span class="o"&gt;=(&lt;/span&gt; &lt;span class="nv"&gt;$array&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
functions &lt;span class="nt"&gt;-M&lt;/span&gt; append 1 1 append
&lt;span class="nb"&gt;declare&lt;/span&gt; &lt;span class="nt"&gt;-a&lt;/span&gt; array&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nv"&gt;array&lt;/span&gt;&lt;span class="o"&gt;=(&lt;/span&gt; &lt;span class="s2"&gt;"Value 1"&lt;/span&gt; &lt;span class="s2"&gt;"Other data"&lt;/span&gt; &lt;span class="s2"&gt;"Value 2"&lt;/span&gt; &lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;declare&lt;/span&gt; &lt;span class="nt"&gt;-a&lt;/span&gt; gathered&lt;span class="p"&gt;;&lt;/span&gt; integer &lt;span class="nv"&gt;idx&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0
: &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;array&lt;/span&gt;&lt;span class="p"&gt;[@]/(#b)(Value ([[&lt;/span&gt;:digit:]]##&lt;span class="p"&gt;)|*)/&lt;/span&gt;&lt;span class="k"&gt;$((&lt;/span&gt; &lt;span class="k"&gt;${#&lt;/span&gt;&lt;span class="nv"&gt;match&lt;/span&gt;&lt;span class="p"&gt;[2]&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; ? append&lt;span class="o"&gt;(++&lt;/span&gt;idx&lt;span class="o"&gt;)&lt;/span&gt; : &lt;span class="o"&gt;++&lt;/span&gt;idx &lt;span class="k"&gt;))}&lt;/span&gt;
print &lt;span class="nv"&gt;$gathered&lt;/span&gt; ▶ Value 1 Value 2
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;Use of &lt;code&gt;#b&lt;/code&gt; glob flag enables math-code execution (and not only) in &lt;code&gt;/&lt;/code&gt; and &lt;code&gt;//&lt;/code&gt; substitutions. Implementation is very&lt;br&gt;
fast.&lt;/p&gt;


&lt;h3&gt;
  
  
  Serializing data
&lt;/h3&gt;




&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;declare&lt;/span&gt; &lt;span class="nt"&gt;-A&lt;/span&gt; hsh deserialized&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nv"&gt;hsh&lt;/span&gt;&lt;span class="o"&gt;=(&lt;/span&gt; key value &lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="nv"&gt;serialized&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="p"&gt;(j&lt;/span&gt;:&lt;span class="p"&gt; &lt;/span&gt;:&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="p"&gt;(qkv@)hsh&lt;/span&gt;&lt;span class="k"&gt;}}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nv"&gt;deserialized&lt;/span&gt;&lt;span class="o"&gt;=(&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="p"&gt;(Q@)&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="p"&gt;(z@)serialized&lt;/span&gt;&lt;span class="k"&gt;}}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;)&lt;/span&gt;
print &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="p"&gt;(kv)deserialized&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; ▶ key value
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;&lt;code&gt;j&lt;/code&gt;-flag means join -- by spaces, in this case. Flags &lt;code&gt;kv&lt;/code&gt; mean: keys and values, interleaving. Important &lt;code&gt;q&lt;/code&gt;-flag&lt;br&gt;
means: quote. So what is obtained is each key and value quoted, and put into a string separated by spaces.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;z&lt;/code&gt;-flag means: split as if Zsh parser would split. So quoting (with backslashes, double quoting, and others) is&lt;br&gt;
recognized. Obtained is array &lt;code&gt;( "key" "value")&lt;/code&gt; which is then de-quoted with &lt;code&gt;Q&lt;/code&gt;-flag. This yields original data,&lt;br&gt;
assigned to hash &lt;code&gt;deserialized&lt;/code&gt;. Use this to e.g. implement an array of hashes.&lt;/p&gt;

&lt;p&gt;Note: to be compatible with &lt;code&gt;setopt ksharrays&lt;/code&gt;, use &lt;code&gt;[@]&lt;/code&gt; instead of &lt;code&gt;(@)&lt;/code&gt;, e.g.:&lt;br&gt;
&lt;code&gt;...( "${(Q)${(z)serialized[@]}[@]}" )&lt;/code&gt;&lt;/p&gt;


&lt;h4&gt;
  
  
  Tip: serializing with Bash
&lt;/h4&gt;




&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;array&lt;/span&gt;&lt;span class="o"&gt;=(&lt;/span&gt; key1 key2 &lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;printf&lt;/span&gt; &lt;span class="nt"&gt;-v&lt;/span&gt; serialized &lt;span class="s2"&gt;"%q "&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;array&lt;/span&gt;&lt;span class="p"&gt;[@]&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nb"&gt;eval&lt;/span&gt; &lt;span class="s2"&gt;"deserialized=(&lt;/span&gt;&lt;span class="nv"&gt;$serialized&lt;/span&gt;&lt;span class="s2"&gt;)"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;This method works also with Zsh. The drawback is the use of &lt;code&gt;eval&lt;/code&gt;, however, no problem may occur unless someone&lt;br&gt;
compromises variable's value, but as always, &lt;code&gt;eval&lt;/code&gt; should be avoided if possible.&lt;/p&gt;


&lt;h2&gt;
  
  
  Real-world examples
&lt;/h2&gt;


&lt;h3&gt;
  
  
  Testing for Git subcommand
&lt;/h3&gt;



&lt;p&gt;Following code checks, if there is a &lt;code&gt;git&lt;/code&gt; subcommand &lt;code&gt;$mysub&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="k"&gt;if &lt;/span&gt;git &lt;span class="nb"&gt;help&lt;/span&gt; &lt;span class="nt"&gt;-a&lt;/span&gt; | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="s2"&gt;"^  [a-z]"&lt;/span&gt; | &lt;span class="nb"&gt;tr&lt;/span&gt; &lt;span class="s1"&gt;' '&lt;/span&gt; &lt;span class="s1"&gt;'\n'&lt;/span&gt; | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-x&lt;/span&gt; &lt;span class="nv"&gt;$mysub&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; /dev/null &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; /dev/null&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;Those are &lt;code&gt;4&lt;/code&gt; forks. The code can be replaced according to this guide:&lt;br&gt;
&lt;/p&gt;

&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;local&lt;/span&gt; &lt;span class="nt"&gt;-a&lt;/span&gt; lines_list
&lt;span class="nv"&gt;lines_list&lt;/span&gt;&lt;span class="o"&gt;=(&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="p"&gt;(f)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;git &lt;span class="nb"&gt;help&lt;/span&gt; &lt;span class="nt"&gt;-a&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; &lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="nv"&gt;lines_list&lt;/span&gt;&lt;span class="o"&gt;=(&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="p"&gt;(M)&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="p"&gt;(s&lt;/span&gt;:&lt;span class="p"&gt; &lt;/span&gt;:&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="p"&gt;(M)lines_list&lt;/span&gt;:#&lt;span class="p"&gt;   [a-z]*&lt;/span&gt;&lt;span class="k"&gt;}}&lt;/span&gt;:#&lt;span class="nv"&gt;$mysub&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; &lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;((&lt;/span&gt; &lt;span class="k"&gt;${#&lt;/span&gt;&lt;span class="nv"&gt;lines_list&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; 0 &lt;span class="o"&gt;))&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
    …
&lt;span class="k"&gt;fi&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;The result is just &lt;code&gt;1&lt;/code&gt; fork.&lt;/p&gt;




&lt;h3&gt;
  
  
  Counting unquoted-only apostrophes
&lt;/h3&gt;




&lt;p&gt;A project was needing this to do some Zle line-continuation tricks (when you put a backslash-\ at the end of the line&lt;br&gt;
and press enters – it is the line-continuation that occurs at that moment).&lt;/p&gt;

&lt;p&gt;The required functionality is: in the given string, count the number of apostrophes, but &lt;em&gt;only the unquoted ones&lt;/em&gt;. This&lt;br&gt;
means that only apostrophes with null or an even number of preceding backslashes should be accepted into the count:&lt;br&gt;
&lt;/p&gt;

&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;buf&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"word'continue&lt;/span&gt;&lt;span class="se"&gt;\'&lt;/span&gt;&lt;span class="s2"&gt;after&lt;/span&gt;&lt;span class="se"&gt;\\\'&lt;/span&gt;&lt;span class="s2"&gt;afterSecnd&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s2"&gt;''afterPair"&lt;/span&gt;
integer &lt;span class="nv"&gt;count&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0
: &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;//(#b)((#s)|[^\\])([\\][\\])#(\&lt;/span&gt;&lt;span class="s1"&gt;'\'&lt;/span&gt;&lt;span class="p"&gt;#)/&lt;/span&gt;&lt;span class="k"&gt;$((&lt;/span&gt; count &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="k"&gt;${#&lt;/span&gt;&lt;span class="nv"&gt;match&lt;/span&gt;&lt;span class="p"&gt;[3]&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; &lt;span class="k"&gt;))}&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nv"&gt;$count&lt;/span&gt; ▶ 3
&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;The answer (i.e. the output) to the above presentation and example is: &lt;code&gt;3&lt;/code&gt; (there are &lt;code&gt;3&lt;/code&gt; unquoted apostrophes in total&lt;br&gt;
in the string kept in the variable &lt;code&gt;$buf&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;Below follows a variation of the above snippet that doesn't use math-code execution:&lt;br&gt;
&lt;/p&gt;

&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;buf&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"word'continue&lt;/span&gt;&lt;span class="se"&gt;\'&lt;/span&gt;&lt;span class="s2"&gt;after&lt;/span&gt;&lt;span class="se"&gt;\\\'&lt;/span&gt;&lt;span class="s2"&gt;afterSecnd&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s2"&gt;''afterPair"&lt;/span&gt;
&lt;span class="nv"&gt;buf&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="p"&gt;(S)buf//(#b)*((#s)|[^\\])([\\][\\])#(\&lt;/span&gt;&lt;span class="s1"&gt;'\'&lt;/span&gt;&lt;span class="p"&gt;#)*/&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;match&lt;/span&gt;&lt;span class="p"&gt;[3]&lt;/span&gt;&lt;span class="k"&gt;}}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nv"&gt;buf&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;%%[^\&lt;/span&gt;&lt;span class="s1"&gt;']##}
integer count=${#buf}
echo $count ▶ 3
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;This is possible thanks to &lt;code&gt;(S)&lt;/code&gt; flag – non-greedy matching, &lt;code&gt;([\\][\\])#&lt;/code&gt; trick – it matches only unquoted following&lt;br&gt;
&lt;code&gt;(\'\'##)&lt;/code&gt; characters (which are the apostrophes) and a general strategy to replace &lt;code&gt;anything-apostrope(s)&lt;/code&gt; (unquoted&lt;br&gt;
ones) with &lt;code&gt;the-apostrope(s)&lt;/code&gt; (and then count them with &lt;code&gt;${#buf}&lt;/code&gt;).&lt;/p&gt;


&lt;h2&gt;
  
  
  Tips and Tricks
&lt;/h2&gt;


&lt;h3&gt;
  
  
  Parsing INI file
&lt;/h3&gt;



&lt;p&gt;With Zshell's &lt;code&gt;extended_glob&lt;/code&gt; parsing an &lt;code&gt;ini&lt;/code&gt; file is an easy task. It will not result in a nested-arrays data&lt;br&gt;
structure (Zsh doesn't support nested hashes), but the hash keys like &lt;code&gt;$DB_CONF[db1_&amp;lt;connection&amp;gt;_host]&lt;/code&gt; is actually&lt;br&gt;
intuitive.&lt;/p&gt;

&lt;p&gt;The code should be placed in a file named &lt;code&gt;read-ini-file&lt;/code&gt;, in &lt;code&gt;$fpath&lt;/code&gt;, and &lt;code&gt;autoload read-ini-file&lt;/code&gt; should be invoked.&lt;br&gt;
&lt;/p&gt;

&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# $1 - path to the ini file to parse&lt;/span&gt;
&lt;span class="c"&gt;# $2 - the name of output hash&lt;/span&gt;
&lt;span class="c"&gt;# $3 - prefix for keys in the hash&lt;/span&gt;
&lt;span class="c"&gt;#&lt;/span&gt;
&lt;span class="c"&gt;# Writes to given hash under keys built-in following way: ${3}&amp;lt;section&amp;gt;_field.&lt;/span&gt;
&lt;span class="c"&gt;# Values are values from the ini file. Example invocation:&lt;/span&gt;
&lt;span class="c"&gt;#&lt;/span&gt;
&lt;span class="c"&gt;# read-ini-file ./database1-setup.ini DB_CONF db1_&lt;/span&gt;
&lt;span class="c"&gt;# read-ini-file ./database2-setup.ini DB_CONF db2_&lt;/span&gt;
&lt;span class="c"&gt;#&lt;/span&gt;

setopt localoptions extendedglob

&lt;span class="nb"&gt;local &lt;/span&gt;&lt;span class="nv"&gt;__ini_file&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nv"&gt;__out_hash&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$2&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nv"&gt;__key_prefix&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$3&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nb"&gt;local &lt;/span&gt;&lt;span class="nv"&gt;IFS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;''&lt;/span&gt; __line &lt;span class="nv"&gt;__cur_section&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"void"&lt;/span&gt; __access_string
&lt;span class="nb"&gt;local&lt;/span&gt; &lt;span class="nt"&gt;-a&lt;/span&gt; match mbegin mend

&lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$__ini_file&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="nb"&gt;builtin &lt;/span&gt;print &lt;span class="nt"&gt;-r&lt;/span&gt; &lt;span class="s2"&gt;"read-ini-file: an ini file is unreadable (&lt;/span&gt;&lt;span class="nv"&gt;$__ini_file&lt;/span&gt;&lt;span class="s2"&gt;)"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;return &lt;/span&gt;1&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;while &lt;/span&gt;&lt;span class="nb"&gt;read&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; &lt;span class="nt"&gt;-t&lt;/span&gt; 1 __line&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do
    if&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$__line&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt;:blank:]]#&lt;span class="se"&gt;\;&lt;/span&gt;&lt;span class="k"&gt;*&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
        continue&lt;/span&gt;
    &lt;span class="c"&gt;# Match "[Section]" line&lt;/span&gt;
    &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$__line&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="c"&gt;#b)[[:blank:]]#\[([^\]]##)\][[:blank:]]# ]]; then&lt;/span&gt;
        &lt;span class="nv"&gt;__cur_section&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;match&lt;/span&gt;&lt;span class="p"&gt;[1]&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
    &lt;span class="c"&gt;# Match "string = string" line&lt;/span&gt;
    &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$__line&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="c"&gt;#b)[[:blank:]]#([^[:blank:]=]##)[[:blank:]]#[=][[:blank:]]#(*) ]]; then&lt;/span&gt;
        match[2]&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;match&lt;/span&gt;&lt;span class="p"&gt;[2]%&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;match&lt;/span&gt;&lt;span class="p"&gt;[2]##*[! &lt;/span&gt;&lt;span class="s1"&gt;$'&lt;/span&gt;&lt;span class="se"&gt;\t&lt;/span&gt;&lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="c"&gt;# severe trick - remove trailing whitespace&lt;/span&gt;
        &lt;span class="nv"&gt;__access_string&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;__out_hash&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;[&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;__key_prefix&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nv"&gt;$__cur_section&lt;/span&gt;&lt;span class="s2"&gt;&amp;gt;_&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;match&lt;/span&gt;&lt;span class="p"&gt;[1]&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;]"&lt;/span&gt;
        : &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="p"&gt;(P)__access_string&lt;/span&gt;::&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;match&lt;/span&gt;&lt;span class="p"&gt;[2]&lt;/span&gt;&lt;span class="k"&gt;}}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;fi
done&lt;/span&gt; &amp;lt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$__ini_file&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

&lt;span class="k"&gt;return &lt;/span&gt;0
&lt;/code&gt;&lt;/pre&gt;



</description>
      <category>zsh</category>
      <category>tutorial</category>
      <category>shell</category>
    </item>
    <item>
      <title>⚙️ ❮ ZSH Plugin Standard ❯</title>
      <dc:creator>Sall</dc:creator>
      <pubDate>Sat, 26 Feb 2022 02:50:09 +0000</pubDate>
      <link>https://dev.to/sso/zsh-plugin-standard-1gpk</link>
      <guid>https://dev.to/sso/zsh-plugin-standard-1gpk</guid>
      <description>&lt;p&gt;&lt;a href="https://github.com/z-shell/zi"&gt;&lt;br&gt;
  &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--qLGRgo7S--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://raw.githubusercontent.com/z-shell/zi/main/docs/images/logo.png" alt="Logo" width="128" height="128"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;

&lt;/h2&gt;
&lt;p&gt;❮ &lt;a href="https://github.com/z-shell/zi"&gt;ZI&lt;/a&gt; ❯&lt;/p&gt;



&lt;p&gt;&lt;a href="https://z.digitalclouds.dev"&gt;https://z.digitalclouds.dev&lt;/a&gt; | &lt;a href="https://github.com/z-shell"&gt;GitHub&lt;/a&gt; | &lt;a href="https://twitter.com/zshell_zi"&gt;Twitter&lt;/a&gt; | &lt;a href="https://github.com/z-shell/community/issues/new?assignees=&amp;amp;labels=%F0%9F%91%A5+member&amp;amp;template=membership.yml&amp;amp;title=team%3A+"&gt;Join the team&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;Table of Contents:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What Is A Zsh Plugin?&lt;/li&gt;
&lt;li&gt;
1. Standardized &lt;code&gt;$0&lt;/code&gt; Handling

&lt;ul&gt;
&lt;li&gt;Adopted [ zero-handling ]&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;
2. Functions Directory

&lt;ul&gt;
&lt;li&gt;Adopted [ functions-directory ]&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;
3. Binaries Directory

&lt;ul&gt;
&lt;li&gt;Adopted [ binaries-directory ]&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;
4. Unload Function

&lt;ul&gt;
&lt;li&gt;Adopted [ unload-function ]&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;
5. &lt;code&gt;@zsh-plugin-run-on-unload&lt;/code&gt; Call

&lt;ul&gt;
&lt;li&gt;Adopted [ run-on-unload-call ]&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;
6. &lt;code&gt;@zsh-plugin-run-on-update&lt;/code&gt; Call

&lt;ul&gt;
&lt;li&gt;Adopted [ run-on-update-call ]&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;
7. Plugin Manager Activity Indicator

&lt;ul&gt;
&lt;li&gt;Adopted [ activity-indicator ]&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;
8. Global Parameter With PREFIX For Make, Configure, Etc

&lt;ul&gt;
&lt;li&gt;Adopted [ global-parameter-with-prefix ]&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;
9. Global Parameter holding the plugin manager’s capabilities

&lt;ul&gt;
&lt;li&gt;Adopted [ global-parameter-with-capabilities ]&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;Zsh Plugin-Programming Best practices&lt;/li&gt;
&lt;li&gt;Use Of &lt;code&gt;add-zsh-hook&lt;/code&gt; To Install Hooks&lt;/li&gt;
&lt;li&gt;Use Of &lt;code&gt;add-zle-hook-widget&lt;/code&gt; To Install Zle Hooks&lt;/li&gt;
&lt;li&gt;Standard Parameter Naming&lt;/li&gt;
&lt;li&gt;Standard &lt;code&gt;Plugins&lt;/code&gt; Hash&lt;/li&gt;
&lt;li&gt;Standard Recommended Options&lt;/li&gt;
&lt;li&gt;Standard Recommended Variables&lt;/li&gt;
&lt;li&gt;Standard Function Name-Space Prefixes&lt;/li&gt;
&lt;li&gt;The Problems Solved By The Proposition&lt;/li&gt;
&lt;li&gt;The Proposed Function-Name Prefixes&lt;/li&gt;
&lt;li&gt;Example Code Utilizing The Prefixes&lt;/li&gt;
&lt;li&gt;Preventing Function Pollution&lt;/li&gt;
&lt;li&gt;Preventing Parameter Pollution&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  What Is A Zsh Plugin?
&lt;/h2&gt;

&lt;p&gt;Historically, Zsh plugins were first defined by Oh My Zsh. They provide a way to package together files that extend or configure the shell’s functionality in a particular way.&lt;/p&gt;

&lt;p&gt;At a simple level, a plugin:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Has its directory added to &lt;code&gt;$fpath&lt;/code&gt; (&lt;a href="http://zsh.sourceforge.net/Doc/Release/Functions.html#Autoloading-Functions"&gt;Zsh documentation&lt;/a&gt;). This is being done either by a plugin manager or by the plugin itself (see 5th section for more information).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Has it's first &lt;code&gt;*.plugin.zsh&lt;/code&gt; file sourced (or &lt;code&gt;*.zsh&lt;/code&gt;, &lt;code&gt;init.zsh&lt;/code&gt;, &lt;code&gt;*.sh&lt;/code&gt;, these are non-standard).&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;2.1 The first point allows plugins to provide completions and functions that are loaded via Zsh’s &lt;code&gt;autoload&lt;/code&gt; mechanism (a single function per file).&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;From a more broad perspective, a plugin consists of:&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;3.1. A directory containing various files (the main script, autoload functions, completions, Makefiles, backend programs, documentation).&lt;/p&gt;

&lt;p&gt;3.2. A sourceable script that obtains the path to its directory via &lt;code&gt;$0&lt;/code&gt; (see the next section for a related enhancement proposal).&lt;/p&gt;

&lt;p&gt;3.3. A Github (or another site) repository identified by two components &lt;strong&gt;username&lt;/strong&gt;/&lt;strong&gt;pluginname&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;3.4. A software package containing any type of command line artifacts – when used with advanced plugin managers that have hooks, can run Makefiles, add directories to &lt;code&gt;$PATH&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Below follow the proposed enhancements and codifications of the definition of a "Zsh the plugin" and the actions of plugin managers – the proposed standardization.&lt;/p&gt;

&lt;p&gt;They cover the information on how to write a Zsh plugin.&lt;/p&gt;




&lt;h2&gt;
  
  
  1. Standardized &lt;code&gt;$0&lt;/code&gt; Handling
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;[ zero-handling ]&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;To get the plugin’s location, plugins should do:&lt;br&gt;
&lt;/p&gt;

&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;0&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;ZERO&lt;/span&gt;&lt;span class="k"&gt;:-${${&lt;/span&gt;&lt;span class="nv"&gt;0&lt;/span&gt;:#&lt;span class="nv"&gt;$ZSH_ARGZERO&lt;/span&gt;&lt;span class="k"&gt;}:-${&lt;/span&gt;&lt;span class="p"&gt;(%)&lt;/span&gt;&lt;span class="k"&gt;:-&lt;/span&gt;&lt;span class="p"&gt;%N&lt;/span&gt;&lt;span class="k"&gt;}}}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nv"&gt;0&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${${&lt;/span&gt;&lt;span class="p"&gt;(M)0&lt;/span&gt;:#/&lt;span class="p"&gt;*&lt;/span&gt;&lt;span class="k"&gt;}:-&lt;/span&gt;&lt;span class="nv"&gt;$PWD&lt;/span&gt;&lt;span class="p"&gt;/&lt;/span&gt;&lt;span class="nv"&gt;$0&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;



&lt;ul&gt;
&lt;li&gt;Then &lt;code&gt;${0:h}&lt;/code&gt; to get the plugin’s directory.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The one-line code above will:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Be backward-compatible with normal &lt;code&gt;$0&lt;/code&gt; setting and usage.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Use &lt;code&gt;ZERO&lt;/code&gt; if it’s not empty,&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;the plugin manager will be easily able to alter effective &lt;code&gt;$0&lt;/code&gt; before loading a plugin,&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;this allows e.g. &lt;code&gt;eval "$(&amp;lt;plugin)"&lt;/code&gt;, which can be faster than &lt;code&gt;source&lt;/code&gt; (&lt;a href="http://www.zsh.org/mla/workers/2017/msg01827.html"&gt;comparison&lt;/a&gt; note that it’s not for a compiled script).&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;Use &lt;code&gt;$0&lt;/code&gt; if it doesn’t contain the path to the Zsh binary,&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;plugin manager will still be able to set &lt;code&gt;$0&lt;/code&gt;, although more difficultly (requires &lt;code&gt;unsetopt function_argzero&lt;/code&gt; before sourcing plugin script, and &lt;code&gt;0=…​&lt;/code&gt; assignment),&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;unsetopt function_argzero&lt;/code&gt; will be detected (it causes &lt;code&gt;$0&lt;/code&gt; not to contain a plugin-script path, but the path to Zsh binary, if not overwritten by a &lt;code&gt;0=…​&lt;/code&gt; assignment),&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;setopt posix_argzero&lt;/code&gt; will be detected (as above).&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;Use &lt;code&gt;%N&lt;/code&gt; prompt expansion flag, which always gives absolute path to script,&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;plugin manager cannot alter this (no advanced loading of plugin is possible), but simple plugin-file sourcing (without a plugin manager) will be saved from breaking caused by the mentioned &lt;code&gt;*_argzero&lt;/code&gt; options, so this is a very good last-resort fallback.&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;Finally, in the second line, it will ensure that &lt;code&gt;$0&lt;/code&gt; contains an absolute path by prepending it with &lt;code&gt;$PWD&lt;/code&gt; if necessary.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The goal is flexibility, with essential motivation to support &lt;code&gt;eval "$(&amp;lt;plugin)"&lt;/code&gt; and definitely solve &lt;code&gt;setopt no_function_argzero&lt;/code&gt; and &lt;code&gt;setopt posix_argzero&lt;/code&gt; cases.&lt;/p&gt;

&lt;p&gt;A plugin manager will be even able to convert a plugin to a function (author implemented such proof of concept functionality, it’s fully possible – also in an automatic fashion), but performance differences of this are yet unclear.&lt;/p&gt;

&lt;p&gt;It might however provide a use case.&lt;/p&gt;

&lt;p&gt;The last, 5th point also allows using the &lt;code&gt;$0&lt;/code&gt; handling in scripts (i.e. runnable with the hashbang &lt;code&gt;#!…&lt;/code&gt;) to get the directory in which the script file resides.&lt;/p&gt;

&lt;p&gt;The assignment uses quoting to make it resilient to the combination of &lt;code&gt;GLOB_SUBST&lt;/code&gt; and &lt;code&gt;GLOB_ASSIGN&lt;/code&gt; options. It’s a standard snippet of code, so it has to be always working.&lt;/p&gt;

&lt;p&gt;When you’ll set e.g.: the &lt;code&gt;zsh&lt;/code&gt; emulation in a function, you in general don’t have to quote assignments.&lt;/p&gt;

&lt;h3&gt;
  
  
  Adopted [ zero-handling ]
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Plugin managers: &lt;a href="https://github.com/z-shell/zi"&gt;ZI&lt;/a&gt;, &lt;a href="https://github.com/zdharma-continuum/zinit"&gt;Zinit&lt;/a&gt;, &lt;a href="https://github.com/zpm-zsh/zpm"&gt;Zpm&lt;/a&gt;, &lt;a href="https://github.com/jandamm/zgenom"&gt;Zgenom&lt;/a&gt;, Zgen (after and if the &lt;a href="https://github.com/tarjoilija/zgen/pull/124"&gt;PR&lt;/a&gt; will be merged).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Plugins: &lt;a href="https://github.com/search?q=%22${ZERO:-${0:%23$ZSH_ARGZERO}}%22&amp;amp;type=Code"&gt;GitHub search&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  2. Functions Directory
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;[ functions-directory ]&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Despite that, the current-standard plugins have their main directory added to &lt;code&gt;$fpath&lt;/code&gt;, a more clean approach is being proposed:&lt;/p&gt;

&lt;p&gt;that the plugins use a subdirectory called &lt;code&gt;functions&lt;/code&gt; to store their completions and autoload functions. This will allow a much cleaner design of plugins.&lt;/p&gt;

&lt;p&gt;The plugin manager should add such a directory to &lt;code&gt;$fpath&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The lack of support of the current plugin managers can be easily resolved via the indicator:&lt;br&gt;
&lt;/p&gt;

&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;zsh_loaded_plugins&lt;/span&gt;&lt;span class="p"&gt;[-1]&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt;/kalc &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nt"&gt;-z&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;fpath&lt;/span&gt;&lt;span class="p"&gt;[(r)&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;0&lt;/span&gt;:h&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="p"&gt;/functions]&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    fpath+&lt;span class="o"&gt;=(&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;0&lt;/span&gt;:h&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/functions"&lt;/span&gt; &lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;or, via use of the &lt;code&gt;PMSPEC&lt;/code&gt; parameter:&lt;br&gt;
&lt;/p&gt;

&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="nv"&gt;$PMSPEC&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt;f&lt;span class="k"&gt;*&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    fpath+&lt;span class="o"&gt;=(&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;0&lt;/span&gt;:h&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/functions"&lt;/span&gt; &lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;The above snippet added to the &lt;code&gt;plugin.zsh&lt;/code&gt; file will add the directory to the &lt;code&gt;$fpath&lt;/code&gt; with the compatibility with any new plugin managers preserved.&lt;/p&gt;

&lt;p&gt;The existence of the &lt;code&gt;functions&lt;/code&gt; subdirectory cancels the normal adding of the main plugin directory to &lt;code&gt;$fpath&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Adopted [ functions-directory ]
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Plugin managers: &lt;a href="https://github.com/zpm-zsh/zpm"&gt;Zpm&lt;/a&gt;, &lt;a href="https://github.com/z-shell/zi"&gt;ZI&lt;/a&gt;, &lt;a href="https://github.com/zdharma-continuum/zinit"&gt;Zinit&lt;/a&gt;, &lt;a href="https://github.com/jandamm/zgenom"&gt;Zgenom&lt;/a&gt;.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  3. Binaries Directory
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;[ binaries-directory ]&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Plugins sometimes provide a runnable script or program, either for their internal use or for the end-user.&lt;/p&gt;

&lt;p&gt;It is proposed that for the latter, the plugin shall use a &lt;code&gt;bin/&lt;/code&gt; subdirectory inside its main dir (it is recommended, that for internal use, the runnable be called via the &lt;code&gt;$0&lt;/code&gt; value obtained as described above).&lt;/p&gt;

&lt;p&gt;The runnable should be put into the directory with a &lt;code&gt;+x&lt;/code&gt; access right assigned.&lt;/p&gt;

&lt;p&gt;The task of the plugin manager should be:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Before sourcing the plugin’s script it should test, if the &lt;code&gt;bin/&lt;/code&gt; directory exists within the plugin directory.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If it does, it should add the directory to &lt;code&gt;$PATH&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The plugin manager can also, instead of extending the &lt;code&gt;$PATH&lt;/code&gt;, create a &lt;strong&gt;shim&lt;/strong&gt; (i.e.: a forwarder script) or a symbolic link inside a common directory that’s already added to &lt;code&gt;$PATH&lt;/code&gt; (to limit extending it).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The plugin manager is permitted to do optional things like ensuring &lt;code&gt;+x&lt;/code&gt; access rights on the directory contents.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The &lt;code&gt;$PMSPEC&lt;/code&gt; code letter for the feature is &lt;code&gt;b&lt;/code&gt;, and it allows for the plugin to handle the &lt;code&gt;$PATH&lt;/code&gt; extending itself, via, e.g.:&lt;br&gt;
&lt;/p&gt;

&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="nv"&gt;$PMSPEC&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt;b&lt;span class="k"&gt;*&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    path+&lt;span class="o"&gt;=(&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;0&lt;/span&gt;:h&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/bin"&lt;/span&gt; &lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;



&lt;h3&gt;
  
  
  Adopted [ binaries-directory ]
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Plugin managers: &lt;a href="https://github.com/zpm-zsh/zpm"&gt;Zpm&lt;/a&gt;, &lt;a href="https://github.com/jandamm/zgenom"&gt;Zgenom&lt;/a&gt; (when you set &lt;code&gt;ZGENOM_AUTO_ADD_BIN=1&lt;/code&gt;).&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  4. Unload Function
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;[ unload-function ]&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If a plugin is named e.g. &lt;code&gt;kalc&lt;/code&gt; (and is available via &lt;code&gt;an-user/kalc&lt;/code&gt; plugin-ID), then it can provide a function, &lt;code&gt;kalc_plugin_unload&lt;/code&gt;, that can be called by a plugin manager to undo the effects of loading that plugin.&lt;/p&gt;

&lt;p&gt;A plugin manager can implement its tracking of changes made by a plugin so this is in general optional. However, to properly unload e.g. a prompt, dedicated tracking (easy to do for the plugin creator) can provide better, predictable results.&lt;/p&gt;

&lt;p&gt;Any special, uncommon effects of loading a plugin are possible to undo only by a dedicated function.&lt;/p&gt;

&lt;p&gt;However, an interesting compromise approach is available – to withdraw only the special effects of loading a plugin via the dedicated, plugin-provided function and leave the rest to the plugin manager. The value of such an approach is that maintaining such function (if it is to withdraw &lt;strong&gt;all&lt;/strong&gt; plugin side-effects) can be a daunting task requiring constant monitoring of it during the plugin development process.&lt;/p&gt;

&lt;p&gt;Note that the unload function should contain &lt;code&gt;unfunction $0&lt;/code&gt; (or better &lt;code&gt;unfunction kalc_plugin_unload&lt;/code&gt; etc., for compatibility with the &lt;code&gt;*_argzero&lt;/code&gt; options), to also delete the function itself.&lt;/p&gt;

&lt;h3&gt;
  
  
  Adopted [ unload-function ]
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://github.com/z-shell/zi"&gt;ZI&lt;/a&gt;, implements plugin unloading and calls the function.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;romkatv/powerlevel10k&lt;/code&gt;, is &lt;a href="https://github.com/romkatv/powerlevel10k/blob/f17081ca/internal/p10k.zsh#L5390"&gt;using&lt;/a&gt; the function to execute a specific task: shutdown of the binary, background &lt;a href="https://github.com/romkatv/gitstatus"&gt;gitstatus&lt;/a&gt; demon, with a very good results,&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;agkozak/agkozak-zsh-prompt&lt;/code&gt; is &lt;a href="https://github.com/agkozak/agkozak-zsh-prompt/blob/ed228952d68fea6d5cad3beee869167f76c59606/agkozak-zsh-prompt.plugin.zsh#L992-L1039"&gt;using&lt;/a&gt; the function to completely unload the prompt,&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;agkozak/zsh-z&lt;/code&gt; is &lt;a href="https://github.com/agkozak/zsh-z/blob/16fba5e9d5c4b650358d65e07609dda4947f97e8/zsh-z.plugin.zsh#L680-L698"&gt;using&lt;/a&gt; the function to completly unload the plugin,&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;agkozak/zhooks&lt;/code&gt; is &lt;a href="https://github.com/agkozak/zhooks/blob/628e1e3b8373bf31c26cb154f71c16ebe9d13b51/zhooks.plugin.zsh#L75-L82"&gt;using&lt;/a&gt; the function to completely unload the plugin.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  5. &lt;code&gt;@zsh-plugin-run-on-unload&lt;/code&gt; Call
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;[ run-on-unload-call ]&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The plugin manager can provide a function &lt;code&gt;@zsh-plugin-run-on-unload&lt;/code&gt; which has the following call syntax:&lt;br&gt;
&lt;/p&gt;

&lt;pre class="highlight shell"&gt;&lt;code&gt;@zsh-plugin-run-on-unload &lt;span class="s2"&gt;"{code-snippet-1}"&lt;/span&gt; &lt;span class="s2"&gt;"{code-snippet-2}"&lt;/span&gt; …
&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;The function registers pieces of code to be run by the plugin manager &lt;strong&gt;on unload of the plugin&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The execution of the code should be done by the &lt;code&gt;eval&lt;/code&gt; built-in in the same order as they are passed to the call.&lt;/p&gt;

&lt;p&gt;The code should be executed in the plugin’s directory, in the current shell.&lt;/p&gt;

&lt;p&gt;The mechanism thus provides another way, side to the unload function, for the plugin to participate in the process of unloading it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Adopted [ run-on-unload-call ]
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Plugin managers: &lt;a href="https://github.com/z-shell/zi"&gt;ZI&lt;/a&gt;, &lt;a href="https://github.com/zdharma-continuum/zinit"&gt;Zinit&lt;/a&gt;.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  6. &lt;code&gt;@zsh-plugin-run-on-update&lt;/code&gt; Call
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;[ run-on-update-call ]&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The plugin manager can provide a function &lt;code&gt;@zsh-plugin-run-on-update&lt;/code&gt; which has the following call syntax:&lt;br&gt;
&lt;/p&gt;

&lt;pre class="highlight shell"&gt;&lt;code&gt;@zsh-plugin-run-on-update &lt;span class="s2"&gt;"{code-snippet-1}"&lt;/span&gt; &lt;span class="s2"&gt;"{code-snippet-2}"&lt;/span&gt; …
&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;The function registers pieces of code to be run by the plugin manager on an update of the plugin.&lt;/p&gt;

&lt;p&gt;The execution of the code should be done by the &lt;code&gt;eval&lt;/code&gt; built-in in the same order as they are passed to the call.&lt;/p&gt;

&lt;p&gt;The code should be executed in the plugin’s directory, possibly in a subshell &lt;strong&gt;After downloading any new commits&lt;/strong&gt; to the repository.&lt;/p&gt;

&lt;h3&gt;
  
  
  Adopted [ run-on-update-call ]
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Plugin managers: &lt;a href="https://github.com/z-shell/zi"&gt;ZI&lt;/a&gt;, &lt;a href="https://github.com/zdharma-continuum/zinit"&gt;Zinit&lt;/a&gt;.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  7. Plugin Manager Activity Indicator
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;[ activity-indicator ]&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Plugin managers should set the &lt;code&gt;$zsh_loaded_plugins&lt;/code&gt; array to contain all previously loaded plugins and the plugin currently being loaded (as the last element).&lt;/p&gt;

&lt;p&gt;This will allow any plugin to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Check which plugins are already loaded.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Check if it is being loaded by a plugin manager (i.e. not just sourced).&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The first item allows a plugin to e.g. issue a notice about missing dependencies.&lt;/p&gt;

&lt;p&gt;Instead of issuing a notice, it may be able to satisfy the dependencies from resources it provides.&lt;/p&gt;

&lt;p&gt;For example, the &lt;code&gt;pure&lt;/code&gt; prompt provides a &lt;code&gt;zsh-async&lt;/code&gt; dependency library within its source tree, which is normally a separate project. Consequently, the prompt can decide to source its private copy of &lt;code&gt;zsh-async&lt;/code&gt;, having also reliable &lt;code&gt;$0&lt;/code&gt; defined by the previous section (note: &lt;code&gt;pure&lt;/code&gt; doesn’t normally do this).&lt;/p&gt;

&lt;p&gt;The second item allows a plugin to e.g. set up &lt;code&gt;$fpath&lt;/code&gt;, knowing that plugin manager will not handle this:&lt;br&gt;
&lt;/p&gt;

&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;zsh_loaded_plugins&lt;/span&gt;&lt;span class="p"&gt;[-1]&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt;/kalc &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nt"&gt;-z&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;fpath&lt;/span&gt;&lt;span class="p"&gt;[(r)&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;0&lt;/span&gt;:h&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    fpath+&lt;span class="o"&gt;=(&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;0&lt;/span&gt;:h&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;This will allow the user to reliably source the plugin without using a plugin manager.&lt;/p&gt;

&lt;p&gt;The code uses the wrapping braces around variables (i.e.: e.g.: &lt;code&gt;${fpath…}&lt;/code&gt;) to make it compatible with the &lt;code&gt;KSH_ARRAYS&lt;/code&gt; option and the quoting around &lt;code&gt;${0:h}&lt;/code&gt; to make it compatible with the &lt;code&gt;SH_WORD_SPLIT&lt;/code&gt; option.&lt;/p&gt;

&lt;h3&gt;
  
  
  Adopted [ activity-indicator ]
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Plugin managers: &lt;a href="https://github.com/z-shell/zi"&gt;ZI&lt;/a&gt;, &lt;a href="https://github.com/zdharma-continuum/zinit"&gt;Zinit&lt;/a&gt;, &lt;a href="https://github.com/zpm-zsh/zpm"&gt;Zpm&lt;/a&gt;, &lt;a href="https://github.com/jandamm/zgenom"&gt;Zgenom&lt;/a&gt;, Zgen (after and if the &lt;a href="https://github.com/tarjoilija/zgen/pull/124"&gt;PR&lt;/a&gt; will be merged).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Plugins: &lt;a href="https://github.com/search?q=if+%22zsh_loaded_plugins%22&amp;amp;type=Code"&gt;GitHub search&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  8. Global Parameter With PREFIX For Make, Configure, Etc
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;[ global-parameter-with-prefix ]&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Plugin managers may export the parameter &lt;code&gt;$ZPFX&lt;/code&gt; which should contain a path to a directory dedicated for user-land software, i.e. for directories &lt;code&gt;$ZPFX/bin&lt;/code&gt;, &lt;code&gt;$ZPFX/lib&lt;/code&gt;, &lt;code&gt;$ZPFX/share&lt;/code&gt;, etc.&lt;/p&gt;

&lt;p&gt;The suggested name of the directory is &lt;code&gt;polaris&lt;/code&gt; (e.g.: ZI uses this name and places this directory at &lt;code&gt;~/.zi/polaris&lt;/code&gt; by default).&lt;/p&gt;

&lt;p&gt;Users can then configure hooks (a feature of e.g. zplug and ZI) to invoke e.g. &lt;code&gt;make PREFIX=$ZPFX install&lt;/code&gt; at clone &amp;amp; update of the plugin to install software like e.g. &lt;a href="https://github.com/tj/git-extras"&gt;tj/git-extras&lt;/a&gt;. This is the developing role of Zsh plugin managers as package managers, where &lt;code&gt;.zshrc&lt;/code&gt; has a similar role to Chef or Puppet configuration and allows to &lt;strong&gt;declare&lt;/strong&gt; system state, and have the same state on different accounts/machines.&lt;/p&gt;

&lt;p&gt;No-narration facts-list related to &lt;code&gt;$ZPFX&lt;/code&gt;:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;export ZPFX="$HOME/polaris"&lt;/code&gt; (or e.g. &lt;code&gt;$HOME/.zi/polaris&lt;/code&gt;)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;make PREFIX=$ZPFX install&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;./configure --prefix=$ZPFX&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;cmake -DCMAKE_INSTALL_PREFIX=$ZPFX .&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;zi ice make"PREFIX=$ZPFX install"&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;zi … hook-build:"make PREFIX=$PFX install"&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Adopted [ global-parameter-with-prefix ]
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Plugin managers: &lt;a href="https://github.com/z-shell/zi"&gt;ZI&lt;/a&gt;, &lt;a href="https://github.com/zdharma-continuum/zinit"&gt;Zinit&lt;/a&gt;, &lt;a href="https://github.com/zpm-zsh/zpm"&gt;Zpm&lt;/a&gt;, &lt;a href="https://github.com/jandamm/zgenom"&gt;Zgenom&lt;/a&gt;.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  9. Global Parameter holding the plugin manager’s capabilities
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;[ global-parameter-with-capabilities ]&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The above paragraphs of the standard spec each constitute a capability, a feature of the plugin manager.&lt;/p&gt;

&lt;p&gt;It would make sense that the capabilities are somehow discoverable. To address this, a global parameter called &lt;code&gt;PMSPEC&lt;/code&gt; (from &lt;em&gt;plugin-manager specification&lt;/em&gt;) is proposed.&lt;/p&gt;

&lt;p&gt;It can hold the following Latin letters each informing the plugin, that the plugin manager has support for a given feature:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;0&lt;/code&gt; – the plugin manager provides the &lt;code&gt;ZERO&lt;/code&gt; parameter,&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;f&lt;/code&gt; - … supports the &lt;code&gt;functions/&lt;/code&gt; subdirectory,&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;b&lt;/code&gt; - … supports the &lt;code&gt;bin/&lt;/code&gt; subdirectory,&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;u&lt;/code&gt; - … the unload function,&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;U&lt;/code&gt; - … the &lt;code&gt;@zsh-plugin-run-on-unload&lt;/code&gt; call,&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;p&lt;/code&gt; – … the &lt;code&gt;@zsh-plugin-run-on-update&lt;/code&gt; call,&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;i&lt;/code&gt; – … the &lt;code&gt;zsh_loaded_plugins&lt;/code&gt; activity indicator,&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;P&lt;/code&gt; – … the &lt;code&gt;ZPFX&lt;/code&gt; global parameter,&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;s&lt;/code&gt; – … the &lt;code&gt;PMSPEC&lt;/code&gt; global parameter itself (i.e.: should be always present).&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The contents of the parameter describing a fully-compliant plugin manager should be: &lt;code&gt;0fuUpiPs&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The plugin can then verify the support by, e.g.:&lt;br&gt;
&lt;/p&gt;

&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="nv"&gt;$PMSPEC&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt;f&lt;span class="k"&gt;*&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    fpath+&lt;span class="o"&gt;=(&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;0&lt;/span&gt;:h&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/functions"&lt;/span&gt; &lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;



&lt;h3&gt;
  
  
  Adopted [ global-parameter-with-capabilities ]
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Plugin managers: &lt;a href="https://github.com/z-shell/zi"&gt;ZI&lt;/a&gt;, &lt;a href="https://github.com/zdharma-continuum/zinit"&gt;Zinit&lt;/a&gt;, &lt;a href="https://github.com/zpm-zsh/zpm"&gt;Zpm&lt;/a&gt;, &lt;a href="https://github.com/jandamm/zgenom"&gt;Zgenom&lt;/a&gt;.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Zsh Plugin-Programming Best practices
&lt;/h2&gt;

&lt;p&gt;The document is to define a &lt;strong&gt;Zsh-plugin&lt;/strong&gt; but also to serve as an information source for plugin creators.&lt;/p&gt;

&lt;p&gt;Therefore, it covers also best practices information in this section.&lt;/p&gt;

&lt;h2&gt;
  
  
  Use Of &lt;code&gt;add-zsh-hook&lt;/code&gt; To Install Hooks
&lt;/h2&gt;

&lt;p&gt;Zsh ships with the function &lt;code&gt;add-zsh-hook&lt;/code&gt;. It has the following invocation syntax:&lt;br&gt;
&lt;/p&gt;

&lt;pre class="highlight shell"&gt;&lt;code&gt;add-zsh-hook &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="nt"&gt;-L&lt;/span&gt; | &lt;span class="nt"&gt;-dD&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="nt"&gt;-Uzk&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt; hook &lt;span class="k"&gt;function&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;The command installs a &lt;code&gt;function&lt;/code&gt; as one of the supported zsh &lt;code&gt;hook&lt;/code&gt; entries. which are one of: &lt;code&gt;chpwd&lt;/code&gt;, &lt;code&gt;periodic&lt;/code&gt;, &lt;code&gt;precmd&lt;/code&gt;, &lt;code&gt;preexec&lt;/code&gt;, &lt;code&gt;zshaddhistory&lt;/code&gt;, &lt;code&gt;zshexit&lt;/code&gt;, &lt;code&gt;zsh_directory_name&lt;/code&gt;. For their meaning refer to the &lt;a href="http://zsh.sourceforge.net/Doc/Release/Functions.html#Hook-Functions"&gt;Zsh documentation&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Use Of &lt;code&gt;add-zle-hook-widget&lt;/code&gt; To Install Zle Hooks
&lt;/h2&gt;

&lt;p&gt;The zle editor is the part of the Zsh that is responsible for receiving the text from the user.&lt;/p&gt;

&lt;p&gt;It can be said that it’s based on widgets, which are nothing more than Zsh functions that are allowed to be run in Zle context, i.e. from the Zle editor (plus a few minor differences, like e.g.: the &lt;code&gt;$WIDGET&lt;/code&gt; parameter that’s automatically set by the Zle editor).&lt;/p&gt;

&lt;p&gt;The syntax of the call is:&lt;br&gt;
&lt;/p&gt;

&lt;pre class="highlight shell"&gt;&lt;code&gt;add-zle-hook-widget &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="nt"&gt;-L&lt;/span&gt; | &lt;span class="nt"&gt;-dD&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="nt"&gt;-Uzk&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt; hook widgetname
&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;The call resembles the syntax of the &lt;code&gt;add-zsh-hook&lt;/code&gt; function. The only difference is that it takes a &lt;code&gt;widgetname&lt;/code&gt;, not a function name and that the &lt;code&gt;hook&lt;/code&gt; is being one of: &lt;code&gt;isearch-exit&lt;/code&gt;, &lt;code&gt;isearch-update&lt;/code&gt;, &lt;code&gt;line-pre-redraw&lt;/code&gt;, &lt;code&gt;line-init&lt;/code&gt;, &lt;code&gt;line-finish&lt;/code&gt;, &lt;code&gt;history-line-set&lt;/code&gt;, or &lt;code&gt;keymap-select&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Their meaning is explained in the &lt;a href="http://zsh.sourceforge.net/Doc/Release/Zsh-Line-Editor.html#Special-Widgets"&gt;Zsh documentation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The use of this function is recommended because it allows the installation &lt;strong&gt;multiple&lt;/strong&gt; hooks per each &lt;code&gt;hook&lt;/code&gt; entry. Before introducing the &lt;code&gt;add-zle-hook-widget&lt;/code&gt; function the "normal" way to install a hook was to define a widget with the name of one of the special widgets.&lt;/p&gt;

&lt;p&gt;Now, after the function has been introduced in Zsh &lt;code&gt;5.3&lt;/code&gt; it should be used instead.&lt;/p&gt;




&lt;h2&gt;
  
  
  Standard Parameter Naming
&lt;/h2&gt;

&lt;p&gt;There’s a convention already present in the Zsh world – to name array variables lowercase and scalars uppercase. It’s being followed by e.g.: the Zsh manual and the Z shell itself (e.g.: &lt;code&gt;REPLY&lt;/code&gt; scalar and &lt;code&gt;reply&lt;/code&gt; array, etc.).&lt;/p&gt;

&lt;p&gt;The requirement for the scalars to be uppercase should be, in my opinion, kept only for the global parameters. I.e.: it’s fine to name local parameters inside a function lowercase even when they are scalars, not only arrays.&lt;/p&gt;

&lt;p&gt;An extension to the convention is being proposed: to name associative arrays (i.e.: hashes) capitalized, i.e.: with only first letter uppercase and the remaining letters lowercase.&lt;/p&gt;

&lt;p&gt;See the next section for an example of such hash. In the case of the name consisting of multiple words each of them should be capitalized, e.g.: &lt;code&gt;typeset -A MyHash&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This convention will increase code readability and bring order to it.&lt;/p&gt;




&lt;h2&gt;
  
  
  Standard &lt;code&gt;Plugins&lt;/code&gt; Hash
&lt;/h2&gt;

&lt;p&gt;The plugin often has to declare global parameters that should live throughout a Zsh session. Following the namespace pollution prevention the plugin could use a hash to store the different values.&lt;/p&gt;

&lt;p&gt;Additionally, the plugins could use a single hash parameter – called &lt;code&gt;Plugins&lt;/code&gt; – to prevent the pollution even more:&lt;br&gt;
&lt;/p&gt;

&lt;pre class="highlight shell"&gt;&lt;code&gt;…
&lt;span class="nb"&gt;typeset&lt;/span&gt; &lt;span class="nt"&gt;-gA&lt;/span&gt; Plugins
&lt;span class="c"&gt;# An example value needed by the plugin&lt;/span&gt;
Plugins[MY_PLUGIN_REPO_DIR]&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;0&lt;/span&gt;:h&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;This way all the data of all plugins will be kept in a single parameter, available for easy examination and overview (via e.g.: &lt;code&gt;varied Plugins&lt;/code&gt;) and also not polluting the namespace.&lt;/p&gt;




&lt;h2&gt;
  
  
  Standard Recommended Options
&lt;/h2&gt;

&lt;p&gt;The following code snippet is recommended to be included at the beginning of each of the main functions provided by the plugin:&lt;br&gt;
&lt;/p&gt;

&lt;pre class="highlight shell"&gt;&lt;code&gt;emulate &lt;span class="nt"&gt;-L&lt;/span&gt; zsh
setopt extended_glob warn_create_global typeset_silent &lt;span class="se"&gt;\&lt;/span&gt;
        no_short_loops rc_quotes no_auto_pushd
&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;It resets all the options to their default state according to the &lt;code&gt;zsh&lt;/code&gt; emulation mode, with the use of the &lt;code&gt;local_options&lt;/code&gt; option – so the options will be restored to their previous state when leaving the function.&lt;/p&gt;

&lt;p&gt;It then alters the emulation by &lt;code&gt;6&lt;/code&gt; different options:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;extended_glob&lt;/code&gt; – enables one of the main Zshell features – the advanced, built-in regex-like globing mechanism,&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;warn_create_global&lt;/code&gt; – enables warnings to be printed each time a (global) the variable is defined without being explicitly defined by a &lt;code&gt;typeset&lt;/code&gt;, &lt;code&gt;local&lt;/code&gt;, &lt;code&gt;declare&lt;/code&gt;, etc. call; it allows to catch typos and missing localizations of the variables and thus prevent from writing a bad code,&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;typeset_silent&lt;/code&gt; – it allows to call &lt;code&gt;typeset&lt;/code&gt;, &lt;code&gt;local&lt;/code&gt;, etc. multiple times on the same variable; without it, the second call causes the variable contents to be printed first; using this option allows declaring variables inside loops, near the place of their use, which sometimes helps to write a more readable code,&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;no_short_loops&lt;/code&gt; – disables the short-loops syntax; this is done because when the syntax is enabled it limits the parser’s ability to detect errors (see this &lt;a href="https://www.zsh.org/mla/workers/2011/msg01050.html"&gt;zsh-workers post&lt;/a&gt; for the details),&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;rc_quotes&lt;/code&gt; – adds useful ability to insert apostrophes into an apostrophe-quoted string, by use of &lt;code&gt;''&lt;/code&gt; inside it, e.g.: &lt;code&gt;'a string’s example'&lt;/code&gt; will yield the string &lt;code&gt;a string’s example&lt;/code&gt;,&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;no_auto_pushd&lt;/code&gt; - disables the automatic push of the directory passed to &lt;code&gt;cd&lt;/code&gt; builtin onto the directory stack; this is useful because otherwise, the internal directory changes done by the plugin will pollute the global directory stack.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Standard Recommended Variables
&lt;/h2&gt;

&lt;p&gt;It’s good to localize the following variables at the entry of the main function of a plugin:&lt;br&gt;
&lt;/p&gt;

&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;local &lt;/span&gt;MATCH REPLY&lt;span class="p"&gt;;&lt;/span&gt; integer MBEGIN MEND
&lt;span class="nb"&gt;local&lt;/span&gt; &lt;span class="nt"&gt;-a&lt;/span&gt; match mbegin mend reply
&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;The variables starting with &lt;code&gt;m&lt;/code&gt; and &lt;code&gt;M&lt;/code&gt; are being used by the substitutions utilizing &lt;code&gt;(#b)&lt;/code&gt; and &lt;code&gt;(#m)&lt;/code&gt; flags, respectively. They should not leak to the global scope. Also, their automatic creation would trigger the warning from the &lt;code&gt;warn_create_global&lt;/code&gt; option.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;reply&lt;/code&gt; and &lt;code&gt;REPLY&lt;/code&gt; parameters are being normally used to return an array or a scalar from a function, respectively – it’s the standard way of passing values from functions.&lt;/p&gt;

&lt;p&gt;Their use is naturally limited to the functions called from the main function of a plugin – they should not be used to pass data around e.g.: in between prompts, thus it’s natural to localize them in the main function.&lt;/p&gt;




&lt;h2&gt;
  
  
  Standard Function Name-Space Prefixes
&lt;/h2&gt;

&lt;p&gt;The recommendation is the purely subjective opinion of the author.&lt;/p&gt;

&lt;p&gt;It can evolve – if you have any remarks, don’t hesitate to &lt;a href="https://github.com/z-shell/zw/issues/new"&gt;fill them&lt;/a&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Problems Solved By The Proposition
&lt;/h2&gt;

&lt;p&gt;However, when adopted, the proposition will solve the following issues:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Using the underscore &lt;code&gt;_&lt;/code&gt; to namespace functions – this isn’t the right thing to do because the prefix is being already used by the completion functions, so the namespace is already filled up greatly and the plugin functions get lost in it.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Not using a prefix at all – this is also an unwanted practice as it pollutes the command namespace (&lt;a href="https://github.com/z-shell/fast-syntax-highlighting/issues/157"&gt;an example&lt;/a&gt; of such issue appearing).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;It would allow to quickly discriminate between function types – e.g.: seeing the &lt;code&gt;:&lt;/code&gt; prefix informs the user that it’s a hook-type function while seeing the &lt;code&gt;@&lt;/code&gt; prefix informs the user that it’s an API-like function, etc.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;It also provides an improvement during programming, by allowing to quickly limit the number of completions offered by the editor, e.g.: for Vim’s &lt;code&gt;Ctrl-P&lt;/code&gt; completing, when entering &lt;code&gt;+&amp;lt;Ctrl-P&amp;gt;&lt;/code&gt;, then only a subset of the functions are being completed (see below for the type of the functions). &lt;strong&gt;Note:&lt;/strong&gt; the editor has to be configured so that it accepts such special characters as part of keywords, for Vim it’s: &lt;code&gt;:set isk+=@-@,.,+,/,:&lt;/code&gt; for all of the proposed prefixes.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  The Proposed Function-Name Prefixes
&lt;/h2&gt;

&lt;p&gt;The proposition of the standard prefixes is as follows:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;.&lt;/code&gt;: for regular private functions. Example function: &lt;code&gt;.prompt_zinc_get_value&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;→&lt;/code&gt;: for hook-like functions, so it should be used e.g.: for the Zsh hooks and the Zle hooks, but also any other, custom hook-like mechanism in the plugin. Example function name: &lt;code&gt;→prompt_zinc_precmd&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;2.1. the previous version of the document recommended colon (&lt;code&gt;:&lt;/code&gt;) for the prefix, however, it was problematic, because Windows doesn’t allow colons in file names, so it wasn’t possible to name an autoload function this way.&lt;/p&gt;

&lt;p&gt;2.2. the arrow has a rationale behind it - it denotes the execution &lt;strong&gt;coming back&lt;/strong&gt; to the function at a later time after it has been registered as a callback or a handler,&lt;/p&gt;

&lt;p&gt;2.3. the arrow is easy to type on most keyboard layouts – it is &lt;code&gt;Right-Alt&lt;/code&gt;+&lt;code&gt;I&lt;/code&gt;; in case of problems with typing the character can be always copied – handler functions do occur in the code rarely,&lt;/p&gt;

&lt;p&gt;2.4. Zsh supports any string as a function name because absolutely any string can be a &lt;strong&gt;file&lt;/strong&gt; name – if there would be an exception in the name of the callables, then how would it be possible to run a script called "→abcd"? There are &lt;strong&gt;no&lt;/strong&gt; exceptions, the function can be called even as the sequence of null bytes:&lt;br&gt;
&lt;/p&gt;

&lt;pre class="highlight shell"&gt;&lt;code&gt;    ❯ &lt;span class="s1"&gt;$'&lt;/span&gt;&lt;span class="se"&gt;\0&lt;/span&gt;&lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; print hello &lt;span class="o"&gt;}&lt;/span&gt;
    ❯ &lt;span class="s1"&gt;$'&lt;/span&gt;&lt;span class="se"&gt;\0&lt;/span&gt;&lt;span class="s1"&gt;'&lt;/span&gt;
    hello
&lt;/code&gt;&lt;/pre&gt;



&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;+&lt;/code&gt;: for output functions, i.e.: for functions that print to the standard output and error or a log, etc. Example function name: &lt;code&gt;+prompt_zinc_output_segment&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;/&lt;/code&gt;: for debugging functions, i.e: for functions that output debugs messages to the screen or a log or e.g.: gather some debug data. &lt;strong&gt;Note:&lt;/strong&gt; the slash makes it impossible for such functions to be auto-loaded via the &lt;code&gt;autoload&lt;/code&gt; mechanism. It is somewhat risky to assume, that this will never be needed for the functions, however, the limited number of available ASCII characters justifies such allocation. Example function name: &lt;code&gt;/prompt_zinc_dmsg&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;@&lt;/code&gt;: for API-like functions, i.e: for functions that are on a boundary to a subsystem and expose its functionality through a well-defined, in the generally fixed interface. For example, this plugin standard defines the function &lt;code&gt;@zsh-plugin-run-on-update&lt;/code&gt;, which is exposing a plugin manager’s functionality in a well-defined way.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Example Code Utilizing The Prefixes
&lt;/h2&gt;



&lt;pre class="highlight shell"&gt;&lt;code&gt;.zinc_register_hooks&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    add-zsh-hook precmd :zinc_precmd
    /zinc_dmsg &lt;span class="s2"&gt;"Installed precmd hook with result: &lt;/span&gt;&lt;span class="nv"&gt;$?&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
    @zsh-plugin-run-on-unload &lt;span class="s2"&gt;"add-zsh-hook -d precmd :zinc_precmd"&lt;/span&gt;
    +zinc_print &lt;span class="s2"&gt;"Zinc initialization complete"&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;






&lt;h2&gt;
  
  
  Preventing Function Pollution
&lt;/h2&gt;

&lt;p&gt;When writing a larger autoload function, it very often is the case that the function contains definitions of other functions.&lt;/p&gt;

&lt;p&gt;When the main function finishes executing, the functions are being left defined. This might be undesired, e.g.: because of the command namespace pollution. The following snippet of code, when added at the beginning of the main function will automatically unset the sub-functions when leaving the main function:&lt;br&gt;
&lt;/p&gt;

&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Don't leak any functions into the global namespace&lt;/span&gt;
&lt;span class="nb"&gt;typeset&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; prjef
&lt;span class="nv"&gt;prjef&lt;/span&gt;&lt;span class="o"&gt;=(&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="p"&gt;(k)functions&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; &lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;trap&lt;/span&gt; &lt;span class="s2"&gt;"unset -f -- &lt;/span&gt;&lt;span class="se"&gt;\"\$&lt;/span&gt;&lt;span class="s2"&gt;{(k)functions[@]:|prjef}&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt; &amp;amp;&amp;gt;/dev/null; unset prjef"&lt;/span&gt; EXIT
&lt;span class="nb"&gt;trap&lt;/span&gt; &lt;span class="s2"&gt;"unset -f -- &lt;/span&gt;&lt;span class="se"&gt;\"\$&lt;/span&gt;&lt;span class="s2"&gt;{(k)functions[@]:|prjef}&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt; &amp;amp;&amp;gt;/dev/null; unset prjef; return 1"&lt;/span&gt; INT
&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;Replace the &lt;code&gt;prj*&lt;/code&gt; prefix with your project name, e.g.: &lt;code&gt;rustef&lt;/code&gt; for a &lt;code&gt;rust&lt;/code&gt;-related plugin. The &lt;code&gt;*ef&lt;/code&gt; stands for "entry functions". The snippet works as follows:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;The line &lt;code&gt;prjef=( ${(k)functions} )&lt;/code&gt; remembers all the functions that are currently defined – which means that the list excludes the functions that are to be yet defined by the body of the main function.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The code &lt;code&gt;unset -f — "${(k)functions[@]:|prjef}"&lt;/code&gt; first does a subtraction of array contents – the &lt;code&gt;:|&lt;/code&gt; substitution operator – of the functions that are defined at the moment of leaving of the function (the &lt;code&gt;trap&lt;/code&gt;-s invoke the code in this moment) with the list of functions from the start of the main function – the ones stored in the variables &lt;code&gt;$prjef&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;It then unsets the resulting list of the functions – being only the newly defined functions in the main function – by passing it to &lt;code&gt;unset -f …&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This way the functions defined by the body of the main (most often an autoload) function will be only set during the execution of the function.&lt;/p&gt;




&lt;h2&gt;
  
  
  Preventing Parameter Pollution
&lt;/h2&gt;

&lt;p&gt;When writing a plugin one often needs to keep a state during the Zsh session. To do this it is natural to use global parameters. However, when the number of the parameters grows one might want to limit it.&lt;/p&gt;

&lt;p&gt;With the following method, only a single global parameter per plugin can be sufficient:&lt;br&gt;
&lt;/p&gt;

&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;typeset&lt;/span&gt; &lt;span class="nt"&gt;-A&lt;/span&gt; PlgMap
&lt;span class="nb"&gt;typeset&lt;/span&gt; &lt;span class="nt"&gt;-A&lt;/span&gt; SomeMap
&lt;span class="nb"&gt;typeset&lt;/span&gt; &lt;span class="nt"&gt;-a&lt;/span&gt; some_array

&lt;span class="c"&gt;# Use&lt;/span&gt;

PlgMap[state]&lt;span class="o"&gt;=&lt;/span&gt;1
SomeMap[state]&lt;span class="o"&gt;=&lt;/span&gt;1
some_array[1]&lt;span class="o"&gt;=&lt;/span&gt;state
&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;can be converted into:&lt;br&gt;
&lt;/p&gt;

&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;typeset&lt;/span&gt; &lt;span class="nt"&gt;-A&lt;/span&gt; PlgMap

&lt;span class="c"&gt;# Use&lt;/span&gt;

PlgMap[state]&lt;span class="o"&gt;=&lt;/span&gt;1
PlgMap[SomeMap__state]&lt;span class="o"&gt;=&lt;/span&gt;1
PlgMap[some_array__1]&lt;span class="o"&gt;=&lt;/span&gt;state
&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;The use of this method is very unproblematic.&lt;/p&gt;

&lt;p&gt;The author reduced the number of global parameters in one of the projects by 21 by using an automatic conversion with Vim substitution patterns with backreferences without any problems.&lt;/p&gt;

&lt;p&gt;Following the Standard Plugins Hash section, the plugin could even use a common hash name – &lt;code&gt;Plugins&lt;/code&gt; – to lower the pollution even more.&lt;br&gt;
 patterns with backreferences without any problems.&lt;/p&gt;

&lt;p&gt;Following the Standard Plugins Hash section, the plugin could even use a common hash name – &lt;code&gt;Plugins&lt;/code&gt; – to lower the pollution even more.&lt;/p&gt;

</description>
      <category>zsh</category>
      <category>tooling</category>
      <category>tutorial</category>
      <category>shell</category>
    </item>
    <item>
      <title>⚙️ ❮ ZBrowse ❯</title>
      <dc:creator>Sall</dc:creator>
      <pubDate>Sat, 19 Feb 2022 20:17:55 +0000</pubDate>
      <link>https://dev.to/sso/zbrowse-20ae</link>
      <guid>https://dev.to/sso/zbrowse-20ae</guid>
      <description>&lt;p&gt;&lt;a href="https://z.digitalclouds.dev"&gt;https://z.digitalclouds.dev&lt;/a&gt; | &lt;a href="https://github.com/z-shell"&gt;GitHub&lt;/a&gt; | &lt;a href="https://twitter.com/zshell_zi"&gt;Twitter&lt;/a&gt;&lt;/p&gt;






&lt;p&gt;When doing shell work, it is often the case that &lt;code&gt;echo $variable&lt;/code&gt; is invoked multiple times, to check result of a loop, etc. With ZBrowse, you just need to press Ctrl-B, which invokes the &lt;code&gt;ZBrowse&lt;/code&gt; – &lt;code&gt;Zshell&lt;/code&gt; variable browser:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--aUVnI1WR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://github.com/z-shell/zbrowse/raw/main/docs/images/zbrowse.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--aUVnI1WR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://github.com/z-shell/zbrowse/raw/main/docs/images/zbrowse.png" alt="ZBrowse" width="800" height="388"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;(you can resize the video like any web page)&lt;/p&gt;

&lt;p&gt;&lt;a href="https://asciinema.org/a/122018"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--jRZ2WuRz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://asciinema.org/a/122018.png" alt="asciicast" width="800" height="435"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Install zbrowse
&lt;/h2&gt;

&lt;p&gt;First install the &lt;a href="https://github.com/z-shell/zui"&gt;ZUI&lt;/a&gt; plugin (it's an UI library).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The plugin is "standalone"&lt;/strong&gt;, which means that only sourcing it is needed. So to install, unpack &lt;code&gt;zbrowse&lt;/code&gt; somewhere and add&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="nb"&gt;source&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;where-zbrowse-is&lt;span class="o"&gt;}&lt;/span&gt;/zbrowse.plugin.zsh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;to &lt;code&gt;zshrc&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;If using a plugin manager, then &lt;code&gt;ZI&lt;/code&gt; is recommended, but you can use any other too, and also install with &lt;code&gt;Oh My Zsh&lt;/code&gt; (by copying directory to &lt;code&gt;~/.oh-my-zsh/custom/plugins&lt;/code&gt;).&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://github.com/z-shell/zi"&gt;ZI&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Add &lt;code&gt;zi load z-shell/zbrowse&lt;/code&gt; to your &lt;code&gt;.zshrc&lt;/code&gt; file. ZI will handle cloning the plugin for you automatically the next time you start zsh. To update run &lt;code&gt;zi update z-shell/zbrowse&lt;/code&gt; (&lt;code&gt;update-all&lt;/code&gt; can also be used).&lt;/p&gt;

&lt;h3&gt;
  
  
  Antigen
&lt;/h3&gt;

&lt;p&gt;Add &lt;code&gt;antigen bundle z-shell/zbrowse&lt;/code&gt; to your &lt;code&gt;.zshrc&lt;/code&gt; file. Antigen will handle cloning the plugin for you automatically the next time you start zsh.&lt;/p&gt;

&lt;h3&gt;
  
  
  Oh-My-Zsh
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;&lt;code&gt;cd ~/.oh-my-zsh/custom/plugins&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;git clone git@github.com:z-shell/zbrowse.git&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Add &lt;code&gt;zbrowse&lt;/code&gt; to your plugin list&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Zgen
&lt;/h3&gt;

&lt;p&gt;Add &lt;code&gt;zgen load z-shell/zbrowse&lt;/code&gt; to your .zshrc file in the same place you're doing your other &lt;code&gt;zgen load&lt;/code&gt; calls.&lt;/p&gt;

</description>
      <category>zsh</category>
      <category>tooling</category>
      <category>testing</category>
      <category>shell</category>
    </item>
    <item>
      <title>⚙️ ❮ ZI Crasis ❯</title>
      <dc:creator>Sall</dc:creator>
      <pubDate>Sat, 19 Feb 2022 13:41:02 +0000</pubDate>
      <link>https://dev.to/sso/zi-crasis-11g7</link>
      <guid>https://dev.to/sso/zi-crasis-11g7</guid>
      <description>&lt;h2&gt;
  &lt;a href="https://github.com/z-shell/zi"&gt;
  &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--qLGRgo7S--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://raw.githubusercontent.com/z-shell/zi/main/docs/images/logo.png" alt="Logo" width="128" height="128"&gt;&lt;img&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://z.digitalclouds.dev"&gt;https://z.digitalclouds.dev&lt;/a&gt; | &lt;a href="https://github.com/z-shell"&gt;GitHub&lt;/a&gt; | &lt;a href="https://twitter.com/zshell_zi"&gt;Twitter&lt;/a&gt; | &lt;a href="https://github.com/z-shell/community/issues/new?assignees=&amp;amp;labels=%F0%9F%91%A5+member&amp;amp;template=membership.yml&amp;amp;title=team%3A+"&gt;Join the team&lt;/a&gt;&lt;/p&gt;




&lt;ul&gt;
&lt;li&gt;Introduction&lt;/li&gt;
&lt;li&gt;Installation &amp;amp; Basic Use&lt;/li&gt;
&lt;li&gt;Key Bindings&lt;/li&gt;
&lt;li&gt;Screenshots&lt;/li&gt;
&lt;li&gt;Code Documentation&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Crasis – semigraphical interface to &lt;a href="https://github.com/z-shell/zi"&gt;ZI&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Zsh exposes its parser via &lt;code&gt;(z)&lt;/code&gt; substitution flag.&lt;/p&gt;

&lt;p&gt;Parsing &lt;code&gt;.zshrc&lt;/code&gt; is totally possible.&lt;/p&gt;

&lt;p&gt;This way &lt;code&gt;Crasis&lt;/code&gt; lets you edit your &lt;code&gt;ZI&lt;/code&gt; commands located in &lt;code&gt;.zshrc&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;All in pure &lt;code&gt;Zshell&lt;/code&gt; code.&lt;/p&gt;

&lt;p&gt;No more commenting-out a line with a text editor to disable plugin, cluttering &lt;code&gt;.zshrc&lt;/code&gt;, now you can just &lt;strong&gt;press a button&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://asciinema.org/a/147225"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Eo5q38tg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://asciinema.org/a/147225.png" alt="asciicast" width="800" height="413"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Crasis&lt;/code&gt; uses pure-Zshell &lt;a href="http://github.com/z-shell/zui/"&gt;ZUI&lt;/a&gt; library to create &lt;code&gt;ncurses&lt;/code&gt; interface.&lt;/p&gt;

&lt;h2&gt;
  
  
  Installation &amp;amp; Basic Use
&lt;/h2&gt;

&lt;p&gt;Install &lt;a href="https://github.com/z-shell/zi"&gt;ZI&lt;/a&gt; and add following commands to &lt;code&gt;.zshrc&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;zi light z-shell/zui
zi light z-shell/zi-crasis
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To use, invoke &lt;code&gt;crasis [optional zshrc path]&lt;/code&gt; or press &lt;code&gt;Ctrl-o-k&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Global variables &lt;code&gt;CRASIS_THEME&lt;/code&gt; and &lt;code&gt;CRASIS_LAYOUT&lt;/code&gt; can be used to override configuration file &lt;code&gt;crasis.conf&lt;/code&gt; (located in plugin's&lt;br&gt;
tree), i.e.:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CRASIS_THEME="zdharma-256" CRASIS_LAYOUT="contract" crasis
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;256&lt;/code&gt;-color themes require Zsh &lt;code&gt;5.3&lt;/code&gt; or later.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key Bindings
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Key(s)&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;&amp;lt;&lt;/code&gt;,&lt;code&gt;&amp;gt;&lt;/code&gt; or &lt;code&gt;{&lt;/code&gt;,&lt;code&gt;}&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Horizontal scroll (i.e. left or right)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Ctrl-L&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Redraw of whole display&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Ctrl-U&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Half page up&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Ctrl-D&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Half page down&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Ctrl-P&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Previous line, centered&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Ctrl-N&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Next line, centered&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;[&lt;/code&gt;, &lt;code&gt;]&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Jump to next and previous section (e.g. next plugin or snippet)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;g&lt;/code&gt;, &lt;code&gt;G&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Jump to beginning and end of whole interface&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Show incremental search&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;F1&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Jump to result (in incremental search) and back&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Esc&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Exit incremental search, clearing query&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Ctrl-W&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Delete whole word (in incremental search)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Ctrl-K&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Delete whole line (in incremental search)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Up and down&lt;/td&gt;
&lt;td&gt;Resize text field when editing it (e.g. to make the text fit in)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Screenshots
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--e0DYsfGv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://raw.githubusercontent.com/z-shell/zi-crasis/main/themes/screenshots/clean-256.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--e0DYsfGv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://raw.githubusercontent.com/z-shell/zi-crasis/main/themes/screenshots/clean-256.png" alt="clean-256" width="800" height="452"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Nr5gIBTq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://raw.githubusercontent.com/z-shell/zi-crasis/main/themes/screenshots/zdharma-256.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Nr5gIBTq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://raw.githubusercontent.com/z-shell/zi-crasis/main/themes/screenshots/zdharma-256.png" alt="zdharma-256" width="800" height="481"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Code Documentation
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;Crasis&lt;/code&gt; is a &lt;a href="http://github.com/z-shell/zui/"&gt;ZUI&lt;/a&gt; application.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;ZUI&lt;/code&gt; is a pure-Zshell library where user generates simple text with hyperlinks, which is then turned into active document with buttons.&lt;/p&gt;

&lt;p&gt;Check out &lt;code&gt;Crasis&lt;/code&gt; code documentation: &lt;a href="https://github.com/z-shell/zi-crasis/blob/7ff5b6d0ab290187f0064020372560b1de033fee/zsdoc/crasis.adoc"&gt;Asciidoc&lt;/a&gt;,  &lt;a href="https://github.com/z-shell/zi-crasis/blob/314cc6f71799a1f3399d9d2963b6e070118a229d/zsdoc/pdf/crasis.pdf"&gt;PDF&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>zsh</category>
      <category>tooling</category>
      <category>productivity</category>
      <category>github</category>
    </item>
    <item>
      <title>⚙️ ❮ ZConvey ❯</title>
      <dc:creator>Sall</dc:creator>
      <pubDate>Sat, 19 Feb 2022 05:08:29 +0000</pubDate>
      <link>https://dev.to/sso/zconvey-2e1g</link>
      <guid>https://dev.to/sso/zconvey-2e1g</guid>
      <description>&lt;h2&gt;
  &lt;a href="https://github.com/z-shell/zi"&gt;
  &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--qLGRgo7S--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://raw.githubusercontent.com/z-shell/zi/main/docs/images/logo.png" alt="Logo" width="128" height="128"&gt;&lt;img&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://z.digitalclouds.dev"&gt;https://z.digitalclouds.dev&lt;/a&gt; | &lt;a href="https://github.com/z-shell"&gt;GitHub&lt;/a&gt; | &lt;a href="https://twitter.com/zshell_zi"&gt;Twitter&lt;/a&gt; | &lt;a href="https://github.com/z-shell/community/issues/new?assignees=&amp;amp;labels=%F0%9F%91%A5+member&amp;amp;template=membership.yml&amp;amp;title=team%3A+"&gt;Join the team&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;ZConvey&lt;/strong&gt; integrates multiple Zsh sessions. They are given an ID, optionally a NAME (both unique), and can send commands to each other. &lt;/p&gt;

&lt;p&gt;Use this to switch all your Zshells to given directory, via &lt;code&gt;zc-all cd $PWD&lt;/code&gt;! Also, there's &lt;code&gt;zc-bg-notify&lt;/code&gt; &lt;strong&gt;script&lt;/strong&gt; (not a function), that will show notification under prompt of every active Zsh session. &lt;/p&gt;

&lt;p&gt;You can call this script from any program, Bash or GUI.&lt;/p&gt;

&lt;p&gt;Video – view on &lt;a href="https://asciinema.org/a/156726"&gt;asciinema&lt;/a&gt;. You can resize the video by pressing &lt;code&gt;Ctrl-+&lt;/code&gt; or &lt;code&gt;Cmd-+&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://asciinema.org/a/156726"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--_ylnjhTw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://asciinema.org/a/156726.png" alt="asciicast" width="800" height="445"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Zstyles for ZConvey values being set are the defaults. They must be set before loading the plugin.
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;zstyle &lt;span class="s2"&gt;":plugin:zconvey"&lt;/span&gt; check_interval &lt;span class="s2"&gt;"2"&lt;/span&gt;         &lt;span class="c"&gt;# How often to check if there are new commands (in seconds)&lt;/span&gt;
zstyle &lt;span class="s2"&gt;":plugin:zconvey"&lt;/span&gt; expire_seconds &lt;span class="s2"&gt;"22"&lt;/span&gt;        &lt;span class="c"&gt;# If shell is busy for 22 seconds, the received command will expire and not run&lt;/span&gt;
zstyle &lt;span class="s2"&gt;":plugin:zconvey"&lt;/span&gt; greeting &lt;span class="s2"&gt;"logo"&lt;/span&gt;            &lt;span class="c"&gt;# Display logo at Zsh start ("text" – display text, "none" – no greeting)&lt;/span&gt;
zstyle &lt;span class="s2"&gt;":plugin:zconvey"&lt;/span&gt; ask &lt;span class="s2"&gt;"0"&lt;/span&gt;                    &lt;span class="c"&gt;# zc won't ask for missing data ("1" has the same effect as always using -a option)&lt;/span&gt;
zstyle &lt;span class="s2"&gt;":plugin:zconvey"&lt;/span&gt; ls_after_rename &lt;span class="s2"&gt;"0"&lt;/span&gt;        &lt;span class="c"&gt;# Don't execute zc-ls after doing rename (with zc-rename or zc-take)&lt;/span&gt;
zstyle &lt;span class="s2"&gt;":plugin:zconvey"&lt;/span&gt; use_zsystem_flock &lt;span class="s2"&gt;"1"&lt;/span&gt;      &lt;span class="c"&gt;# Should use faster zsystem's flock when it's possible?&lt;/span&gt;
                                                    &lt;span class="c"&gt;# (default true on Zsh &amp;gt;= 5.3, will revert to mixed zsystem/flock on older Zshells)&lt;/span&gt;
zstyle &lt;span class="s2"&gt;":plugin:zconvey"&lt;/span&gt; output_method &lt;span class="s2"&gt;"feeder"&lt;/span&gt;     &lt;span class="c"&gt;# To put commands on command line, ZConvey can use small program "feeder". Or "zsh"&lt;/span&gt;
                                                    &lt;span class="c"&gt;# method, which currently doesn't automatically run the command – to use when e.g.&lt;/span&gt;
                                                    &lt;span class="c"&gt;# feeder doesn't build (unlikely) or when occurring any problems with it&lt;/span&gt;
zstyle &lt;span class="s2"&gt;":plugin:zconvey"&lt;/span&gt; timestamp_from &lt;span class="s2"&gt;"datetime"&lt;/span&gt;  &lt;span class="c"&gt;# Use zsh/datetime module for obtaining timestamp. "date" – use date command (fork)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  ZConvey commands
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;zc&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Sends to other session; use "-a" option to be asked for target and a command to send&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;zc-ls&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Lists all active and named sessions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;zc-id&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Shows ID and NAME of current session&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;zc-all&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The same as &lt;code&gt;zc&lt;/code&gt;, but targets are all other active sessions (with &lt;code&gt;-f&lt;/code&gt; also busy sessions)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;zc-take&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Takes a name for current or selected sessions, schematically renames any conflicting sessions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;zc-logo&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The same as &lt;code&gt;zc-id&lt;/code&gt;, but in a form of an on-screen logo; bound to Ctrl-O Ctrl-I&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;zc-rename&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Assigns name to current or selected session; won't rename if there's a session with the same name&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;zc-bg-notify&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;In subdirectory &lt;code&gt;cmds&lt;/code&gt;, link it to &lt;code&gt;/usr/local/bin&lt;/code&gt;, etc. or load with e.g. ZI&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The main command is &lt;code&gt;zc&lt;/code&gt; (yet it is rather rarely used, I'm always sending to all sessions with &lt;code&gt;zc-all&lt;/code&gt;). It is used to execute commands on other sessions. &lt;code&gt;zc-ls&lt;/code&gt; is the main tool to obtain overall information on sessions. &lt;code&gt;zc-take&lt;/code&gt; is a nice rename tool to quickly name a few sessions. Keyboard shortcut Ctrl-O Ctrl-I will show current session's ID and NAME in form of an on-screen logo.&lt;/p&gt;

&lt;h2&gt;
  
  
  Install ZConvey with ZI
&lt;/h2&gt;

&lt;p&gt;Add &lt;code&gt;zi load z-shell/zconvey&lt;/code&gt; to your &lt;code&gt;.zshrc&lt;/code&gt; file. ZI will clone the plugin the next time you start zsh. To update issue &lt;code&gt;zi update z-shell/zconvey&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;ZI can load in turbo-mode, below is an example configuration.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;zi ice &lt;span class="nb"&gt;wait&lt;/span&gt;&lt;span class="s2"&gt;"0"&lt;/span&gt;
zi light z-shell/zconvey
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Adding &lt;code&gt;zc-bg-notify&lt;/code&gt; to &lt;code&gt;$PATH&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;zi ice &lt;span class="nb"&gt;wait&lt;/span&gt;&lt;span class="s2"&gt;"0"&lt;/span&gt; as&lt;span class="s2"&gt;"command"&lt;/span&gt; pick&lt;span class="s2"&gt;"cmds/zc-bg-notify"&lt;/span&gt; silent
zi light z-shell/zconvey
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Manual ZConvey installation
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;The plugin is "standalone"&lt;/strong&gt;, which means that only sourcing it is needed. So to install, unpack &lt;code&gt;zconvey&lt;/code&gt; somewhere and add&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="nb"&gt;source&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;where-zconvey-is&lt;span class="o"&gt;}&lt;/span&gt;/zconvey.plugin.zsh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;to &lt;code&gt;zshrc&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;If using a plugin manager, then &lt;code&gt;ZI&lt;/code&gt; is recommended, but you can use any other too, and also install with &lt;code&gt;Oh My Zsh&lt;/code&gt; (by copying directory to &lt;code&gt;~/.oh-my-zsh/custom/plugins&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;The plugin integrates with my other plugin &lt;a href="https://github.com/z-shell/zsh-select"&gt;Zsh-Select&lt;/a&gt;. Install it with e.g. ZI to be able to use &lt;code&gt;-a&lt;/code&gt; option for &lt;code&gt;zc&lt;/code&gt; command.&lt;/p&gt;

</description>
      <category>zsh</category>
      <category>tooling</category>
      <category>opensource</category>
      <category>shell</category>
    </item>
    <item>
      <title>⚙️ ❮ Zsh Select ❯</title>
      <dc:creator>Sall</dc:creator>
      <pubDate>Sat, 19 Feb 2022 03:29:02 +0000</pubDate>
      <link>https://dev.to/sso/zsh-select-4fc0</link>
      <guid>https://dev.to/sso/zsh-select-4fc0</guid>
      <description>&lt;h2&gt;
  &lt;a href="https://github.com/z-shell/zi"&gt;
  &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--qLGRgo7S--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://raw.githubusercontent.com/z-shell/zi/main/docs/images/logo.png" alt="Logo" width="128" height="128"&gt;&lt;img&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://z.digitalclouds.dev"&gt;https://z.digitalclouds.dev&lt;/a&gt; | &lt;a href="https://github.com/z-shell"&gt;GitHub&lt;/a&gt; | &lt;a href="https://twitter.com/zshell_zi"&gt;Twitter&lt;/a&gt; | &lt;a href="https://github.com/z-shell/community/issues/new?assignees=&amp;amp;labels=%F0%9F%91%A5+member&amp;amp;template=membership.yml&amp;amp;title=team%3A+"&gt;Join the team&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;A shell command that will display selection list.&lt;/p&gt;

&lt;p&gt;It is similar to &lt;code&gt;selecta&lt;/code&gt;, but uses curses library to do display, and when compared to &lt;code&gt;fzf&lt;/code&gt;, the main difference is approximate matching instead of fuzzy matching.&lt;/p&gt;

&lt;p&gt;It is written in Zshell and has it's capabilities:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;patterns, allowing multi-term searching&lt;/li&gt;
&lt;li&gt;curses module&lt;/li&gt;
&lt;li&gt;approximate matching (&lt;code&gt;Ctrl-F&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The file &lt;code&gt;zsh-select&lt;/code&gt; can be copied to any &lt;code&gt;bin&lt;/code&gt; directory.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Zsh&lt;/code&gt; will serve as say &lt;code&gt;Ruby&lt;/code&gt;, and &lt;code&gt;zsh-select&lt;/code&gt; will be a regular program available&lt;br&gt;
in system.&lt;/p&gt;

&lt;p&gt;Pressing &lt;code&gt;o&lt;/code&gt; will make elements uniqe.&lt;br&gt;
To search again after pressing enter, press &lt;code&gt;/&lt;/code&gt;. Approximate matching mode is activated by &lt;code&gt;Ctrl-F&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Video: &lt;a href="https://asciinema.org/a/48490"&gt;asciinema&lt;/a&gt;. You can resize the video by pressing &lt;code&gt;Ctrl-+&lt;/code&gt; or &lt;code&gt;Cmd-+&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://asciinema.org/a/48490"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--SIFT9V_3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://asciinema.org/a/48490.png" alt="asciicast" width="800" height="403"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Installation
&lt;/h2&gt;

&lt;p&gt;Simply copy file &lt;code&gt;zsh-select&lt;/code&gt; to any &lt;code&gt;bin&lt;/code&gt; directory such as &lt;code&gt;/usr/local/bin&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The package is also available as plugin. &lt;code&gt;zsh-select&lt;/code&gt; will be available in interactive &lt;code&gt;Zsh&lt;/code&gt; sessions only when using this method.&lt;/p&gt;

&lt;p&gt;Nevertheless, integration with &lt;code&gt;Vim&lt;/code&gt; and other uses will simply work when &lt;code&gt;Zsh&lt;/code&gt; is your main shell.&lt;/p&gt;

&lt;p&gt;Also, plugin managers often allow easy updates.&lt;/p&gt;
&lt;h2&gt;
  
  
  Integration with Vim
&lt;/h2&gt;

&lt;p&gt;Adding following snippet to &lt;code&gt;vimrc&lt;/code&gt; will provide &lt;code&gt;\f&lt;/code&gt; keyboard shortcut that will run &lt;code&gt;zsh-select&lt;/code&gt; as file-selector.&lt;/p&gt;

&lt;p&gt;Multi-term searching and approximate matching&lt;br&gt;
(&lt;code&gt;Ctrl-F&lt;/code&gt;) will be available.&lt;/p&gt;

&lt;p&gt;The snippet is based on code from &lt;code&gt;selecta&lt;/code&gt; github page (MIT license):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight viml"&gt;&lt;code&gt;&lt;span class="c"&gt;" Run a given vim command on the results of fuzzy selecting from a given shell" command. See usage below.&lt;/span&gt;

&lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt; ZshSelectCommand&lt;span class="p"&gt;(&lt;/span&gt;choice_command&lt;span class="p"&gt;,&lt;/span&gt; zshselect_args&lt;span class="p"&gt;,&lt;/span&gt; vim_command&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;try&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nb"&gt;selection&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;system&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;a:choice_command&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="s2"&gt;" | zsh-select "&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="nv"&gt;a:zshselect_args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="sr"&gt;/Vim:Interrupt/&lt;/span&gt;
    &lt;span class="c"&gt;" Swallow the ^C so that the redraw below happens; otherwise there will be&lt;/span&gt;
    &lt;span class="c"&gt;" leftovers from zshselect on the screen&lt;/span&gt;
    &lt;span class="k"&gt;redraw&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt;
  &lt;span class="k"&gt;endtry&lt;/span&gt;
  &lt;span class="k"&gt;redraw&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;
  exec &lt;span class="nv"&gt;a:vim_command&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="s2"&gt;" "&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="nb"&gt;selection&lt;/span&gt;
&lt;span class="k"&gt;endfunction&lt;/span&gt;

&lt;span class="c"&gt;" Find all files in all non-dot directories starting in the working directory.&lt;/span&gt;
&lt;span class="c"&gt;" Fuzzy select one of those. Open the selected file with :e.&lt;/span&gt;
nnoremap &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;leader&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="k"&gt;f&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="k"&gt;call&lt;/span&gt; ZshSelectCommand&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"find * -type f 2&amp;gt;/dev/null"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;":e"&lt;/span&gt;&lt;span class="p"&gt;)&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;cr&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Configuring
&lt;/h2&gt;

&lt;p&gt;There are a few environment variables that can be set to alter &lt;code&gt;Zsh-Select&lt;/code&gt; behavior.&lt;/p&gt;

&lt;p&gt;Values assigned below are the defaults:&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="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;ZSHSELECT_BOLD&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"1"&lt;/span&gt;                   
&lt;span class="c"&gt;# The interface will be drawn in bold font. Use "0" for no bold&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;ZSHSELECT_COLOR_PAIR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"white/black"&lt;/span&gt;   
&lt;span class="c"&gt;# Draw in white foreground, black background. Try e.g.: "white/green"&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;ZSHSELECT_BORDER&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"0"&lt;/span&gt;                 
&lt;span class="c"&gt;# No border around interface, Use "1" for the border&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;ZSHSELECT_ACTIVE_TEXT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"reverse"&lt;/span&gt;      
&lt;span class="c"&gt;# Mark current element with reversed text. Use "underline" for marking with underline&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;ZSHSELECT_START_IN_SEARCH_MODE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"1"&lt;/span&gt;   
&lt;span class="c"&gt;# Starts Zsh-Select with searching active. "0" will not invoke searching at start.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Use with plugin managers
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://github.com/z-shell/zi"&gt;ZI&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Add &lt;code&gt;zi load z-shell/zsh-select&lt;/code&gt; to &lt;code&gt;.zshrc&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The plugin will be loaded next time you start &lt;code&gt;Zsh&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;To update issue &lt;code&gt;zi update z-shell/zsh-select&lt;/code&gt; from command line.&lt;/p&gt;

&lt;h3&gt;
  
  
  Zgen
&lt;/h3&gt;

&lt;p&gt;Add &lt;code&gt;zgen load z-shell/zsh-select&lt;/code&gt; to &lt;code&gt;.zshrc&lt;/code&gt; and issue a &lt;code&gt;zgen reset&lt;/code&gt; (this assumes that there is a proper &lt;code&gt;zgen save&lt;/code&gt; construct in &lt;code&gt;.zshrc&lt;/code&gt;).&lt;/p&gt;

&lt;h3&gt;
  
  
  Antigen
&lt;/h3&gt;

&lt;p&gt;Add &lt;code&gt;antigen bundle z-shell/zsh-select&lt;/code&gt; to &lt;code&gt;.zshrc&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;There also should be &lt;code&gt;antigen apply&lt;/code&gt;.&lt;/p&gt;

</description>
      <category>zsh</category>
      <category>tooling</category>
      <category>vim</category>
      <category>shell</category>
    </item>
    <item>
      <title>⚙️ ❮ Zsh-Py3-HTTP ❯ | Auto Spawned service</title>
      <dc:creator>Sall</dc:creator>
      <pubDate>Wed, 16 Feb 2022 18:59:11 +0000</pubDate>
      <link>https://dev.to/sso/zsh-py3-http-auto-spawned-service-7ip</link>
      <guid>https://dev.to/sso/zsh-py3-http-auto-spawned-service-7ip</guid>
      <description>&lt;h2&gt;
  &lt;a href="https://github.com/z-shell/zi" rel="noopener noreferrer"&gt;
  &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fz-shell%2Fzi%2Fmain%2Fdocs%2Fimages%2Flogo.png" alt="Logo"&gt;&lt;img&gt;&lt;/a&gt;

❮ ZI ❯ Service - Py3HTTP
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://z.digitalclouds.dev" rel="noopener noreferrer"&gt;https://z.digitalclouds.dev&lt;/a&gt; | &lt;a href="https://github.com/z-shell" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt; | &lt;a href="https://twitter.com/zshell_zi" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt; | &lt;a href="https://github.com/z-shell/community/issues/new?assignees=&amp;amp;labels=%F0%9F%91%A5+member&amp;amp;template=membership.yml&amp;amp;title=team%3A+" rel="noopener noreferrer"&gt;Join the team&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;This &lt;strong&gt;Zsh&lt;/strong&gt; service-plugin will serve given directory &lt;em&gt;(plugin's directory by default)&lt;/em&gt; using &lt;strong&gt;Python's 3 HTTP server&lt;/strong&gt;.&lt;/p&gt;




&lt;h3&gt;
  
  
  Install with ❮ &lt;a href="https://github.com/z-shell/zi/" rel="noopener noreferrer"&gt;ZI&lt;/a&gt; ❯
&lt;/h3&gt;

&lt;p&gt;The service-plugin supports loading single plugin instance per all active Zsh sessions, in background.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;zi ice service&lt;span class="s1"&gt;'py3http'&lt;/span&gt;
zi light z-shell/zservice-py3http
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  Explanation of Zsh-spawned services
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;First Zsh instance that will gain a lock will spawn the service.&lt;/li&gt;
&lt;li&gt;Other Zsh instances will wait.&lt;/li&gt;
&lt;li&gt;When you close the initial Zsh session, another Zsh will gain lock and resume the service.&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>zsh</category>
      <category>tooling</category>
      <category>webdev</category>
      <category>python</category>
    </item>
    <item>
      <title>⚙️ ❮ Zsh Unique ID ❯</title>
      <dc:creator>Sall</dc:creator>
      <pubDate>Tue, 15 Feb 2022 20:03:25 +0000</pubDate>
      <link>https://dev.to/sso/zsh-unique-id-55ga</link>
      <guid>https://dev.to/sso/zsh-unique-id-55ga</guid>
      <description>&lt;p&gt;&lt;a href="https://media.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%2Fu4j7yw2itgeth8bumv8c.png" class="article-body-image-wrapper"&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-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu4j7yw2itgeth8bumv8c.png" alt="❮ ZI ❯"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://z.digitalclouds.dev" rel="noopener noreferrer"&gt;https://z.digitalclouds.dev&lt;/a&gt; | &lt;a href="https://github.com/z-shell" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt; | &lt;a href="https://twitter.com/zshell_zi" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt; | &lt;a href="https://github.com/z-shell/community/issues/new?assignees=&amp;amp;labels=%F0%9F%91%A5+member&amp;amp;template=membership.yml&amp;amp;title=team%3A+" rel="noopener noreferrer"&gt;Join the team&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;This plugin provides a &lt;strong&gt;unique number&lt;/strong&gt; that identifies a &lt;strong&gt;running&lt;/strong&gt; Zshell session, in its shell variable &lt;code&gt;$ZUID_ID&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Besides this unique number, also a unique &lt;em&gt;codename&lt;/em&gt; is provided, in shell variable &lt;code&gt;$ZUID_CODENAME&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Once you load this plugin, the two parameters will be set, and their values will not be available to other Zshell sessions (being thus &lt;em&gt;unique&lt;/em&gt;).&lt;/p&gt;

&lt;p&gt;&lt;code&gt;$ZUID_ID&lt;/code&gt; is a progressing number starting from &lt;code&gt;1&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;$ZUID_CODENAME&lt;/code&gt; is chosen from a list of predefined codenames, see the default list below.&lt;/p&gt;

&lt;p&gt;An example use case is to hold logs in files &lt;code&gt;.../mylog-${ZUID_CODENAME}.log&lt;/code&gt;,&lt;/p&gt;

&lt;p&gt;so that two different Zshells will not write to the same file at the same time.&lt;/p&gt;




&lt;p&gt;Default codenames are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;atlantis (for &lt;code&gt;ZUID_ID&lt;/code&gt; == &lt;code&gt;1&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;echelon (for &lt;code&gt;ZUID_ID&lt;/code&gt; == &lt;code&gt;2&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;quantum (etc.)&lt;/li&gt;
&lt;li&gt;ion&lt;/li&gt;
&lt;li&gt;proxima&lt;/li&gt;
&lt;li&gt;polaris&lt;/li&gt;
&lt;li&gt;solar&lt;/li&gt;
&lt;li&gt;momentum&lt;/li&gt;
&lt;li&gt;hyper&lt;/li&gt;
&lt;li&gt;gloom&lt;/li&gt;
&lt;li&gt;velocity&lt;/li&gt;
&lt;li&gt;future&lt;/li&gt;
&lt;li&gt;enigma&lt;/li&gt;
&lt;li&gt;andromeda&lt;/li&gt;
&lt;li&gt;saturn&lt;/li&gt;
&lt;li&gt;jupiter&lt;/li&gt;
&lt;li&gt;aslan&lt;/li&gt;
&lt;li&gt;commodore&lt;/li&gt;
&lt;li&gt;falcon&lt;/li&gt;
&lt;li&gt;persepolis&lt;/li&gt;
&lt;li&gt;dharma&lt;/li&gt;
&lt;li&gt;samsara&lt;/li&gt;
&lt;li&gt;prodigy&lt;/li&gt;
&lt;li&gt;ethereal&lt;/li&gt;
&lt;li&gt;epiphany&lt;/li&gt;
&lt;li&gt;aurora&lt;/li&gt;
&lt;li&gt;oblivion&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Zstyle configuration allows to customize the codenames:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;zstyle :plugin:zuid codenames paper metal wood plastic &lt;span class="c"&gt;# first 4 shells will have those codenames&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Install Zsh Unique ID
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;The plugin is "standalone"&lt;/strong&gt;, which means that only sourcing it is needed (without using a plugin manager).&lt;/p&gt;

&lt;p&gt;So to install, unpack &lt;code&gt;zsh-unique-id&lt;/code&gt; somewhere and add:&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="nb"&gt;source&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;where-zsh-unique-id-is&lt;span class="o"&gt;}&lt;/span&gt;/zsh-unique-id.plugin.zsh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;to &lt;code&gt;zshrc&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Sourcing is recommended, because it can be done early,&lt;br&gt;
 at top of zshrc, without a plugin manager – to acquire the unique identification as early as possible.&lt;/p&gt;

&lt;h3&gt;
  
  
  With &lt;a href="https://github.com/z-shell/zi" rel="noopener noreferrer"&gt;ZI&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Add &lt;code&gt;zi load z-shell/zsh-unique-id&lt;/code&gt; to your &lt;code&gt;.zshrc&lt;/code&gt; file. ZI will clone the plugin the next time you start zsh.&lt;/p&gt;

&lt;p&gt;To update issue &lt;code&gt;zi update z-shell/zsh-unique-id&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  With Antigen
&lt;/h3&gt;

&lt;p&gt;Add &lt;code&gt;antigen bundle z-shell/zsh-unique-id&lt;/code&gt; to your &lt;code&gt;.zshrc&lt;/code&gt; file.&lt;/p&gt;

&lt;p&gt;Antigen will handle cloning the plugin for you automatically the next time you start zsh.&lt;/p&gt;

&lt;h3&gt;
  
  
  With Oh-My-Zsh
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;&lt;code&gt;cd ~/.oh-my-zsh/custom/plugins&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;git clone git@github.com:z-shell/zsh-unique-id.git&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Add &lt;code&gt;zsh-unique-id&lt;/code&gt; to your plugin list.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  With Zgen
&lt;/h3&gt;

&lt;p&gt;Add &lt;code&gt;zgen load z-shell/zsh-unique-id&lt;/code&gt; to your .zshrc file in the same place you're doing your other &lt;code&gt;zgen load&lt;/code&gt; calls in.&lt;/p&gt;

</description>
      <category>zsh</category>
      <category>tooling</category>
      <category>productivity</category>
      <category>shell</category>
    </item>
    <item>
      <title>⚙️ ❮ ZI + Diff-so-Fancy ❯ | Git</title>
      <dc:creator>Sall</dc:creator>
      <pubDate>Tue, 15 Feb 2022 13:57:24 +0000</pubDate>
      <link>https://dev.to/sso/zi-diff-so-fancy-git-4b3c</link>
      <guid>https://dev.to/sso/zi-diff-so-fancy-git-4b3c</guid>
      <description>&lt;p&gt;&lt;a href="https://github.com/z-shell/zi" rel="noopener noreferrer"&gt;&lt;br&gt;
  &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fz-shell%2Fzi%2Fmain%2Fdocs%2Fimages%2Flogo.png" alt="Logo"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;

&lt;/h2&gt;
&lt;p&gt;❮ &lt;a href="https://github.com/z-shell/zi" rel="noopener noreferrer"&gt;ZI&lt;/a&gt; + &lt;a href="https://github.com/z-shell/zsh-diff-so-fancy" rel="noopener noreferrer"&gt;Diff-so-Fancy&lt;/a&gt; ❯&lt;/p&gt;



&lt;p&gt;&lt;a href="https://z.digitalclouds.dev" rel="noopener noreferrer"&gt;https://z.digitalclouds.dev&lt;/a&gt; | &lt;a href="https://github.com/z-shell" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt; | &lt;a href="https://twitter.com/zshell_zi" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt; | &lt;a href="https://github.com/z-shell/community/issues/new?assignees=&amp;amp;labels=%F0%9F%91%A5+member&amp;amp;template=membership.yml&amp;amp;title=team%3A+" rel="noopener noreferrer"&gt;Join the team&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fz-shell%2Fzsh-diff-so-fancy%2Fraw%2Fmain%2Fdocs%2Fimg%2Fzsh-diff-so-fancy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fz-shell%2Fzsh-diff-so-fancy%2Fraw%2Fmain%2Fdocs%2Fimg%2Fzsh-diff-so-fancy.gif" alt="zsh-diff-so-fancy"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;The project &lt;a href="https://github.com/so-fancy/diff-so-fancy" rel="noopener noreferrer"&gt;so-fancy/diff-so-fancy&lt;/a&gt; integration with ZI.&lt;/p&gt;

&lt;p&gt;With this &lt;a href="https://github.com/z-shell/zi" rel="noopener noreferrer"&gt;ZI&lt;/a&gt; plugin, you simply add two lines to &lt;code&gt;.zshrc&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;pre class="highlight shell"&gt;&lt;code&gt;zi ice as&lt;span class="s2"&gt;"program"&lt;/span&gt; pick&lt;span class="s2"&gt;"bin/git-dsf"&lt;/span&gt;
zi light z-shell/zsh-diff-so-fancy
&lt;/code&gt;&lt;/pre&gt;






&lt;p&gt;This will install &lt;code&gt;diff-so-fancy&lt;/code&gt; on every account where you use Zshell, and automatically equip &lt;code&gt;git&lt;/code&gt; with subcommand &lt;code&gt;dsf&lt;/code&gt;. No need to use system package manager and to configure &lt;code&gt;git&lt;/code&gt;. Of course, if you have the following standard line in your &lt;code&gt;.gitconfig&lt;/code&gt;, it will still work normally:&lt;br&gt;
&lt;/p&gt;

&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;[&lt;/span&gt;core]
pager &lt;span class="o"&gt;=&lt;/span&gt; diff-so-fancy | less &lt;span class="nt"&gt;-FXRi&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;(because this plugin adds &lt;code&gt;diff-so-fancy&lt;/code&gt; to &lt;code&gt;$PATH&lt;/code&gt;).&lt;/p&gt;




&lt;p&gt;Think about Puppet or Chef, i.e. about declarative approach to system configuration.&lt;/p&gt;

&lt;p&gt;In this case &lt;code&gt;.zshrc&lt;/code&gt; is like a declarative setup guarding you will have &lt;code&gt;diff-so-fancy&lt;/code&gt;&lt;br&gt;
on your accounts.&lt;/p&gt;

&lt;h3&gt;
  
  
  A Few Details
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://github.com/so-fancy/diff-so-fancy" rel="noopener noreferrer"&gt;so-fancy/diff-so-fancy&lt;/a&gt; is cloned from&lt;br&gt;
Github as submodule. The plugin has &lt;code&gt;bin/git-dsf&lt;/code&gt; script which adds subcommand &lt;code&gt;dsf&lt;/code&gt;&lt;br&gt;
to git.&lt;/p&gt;

&lt;p&gt;That's basically everything needed: convenient way of installing (single Zsh&lt;br&gt;
plugin manager invocation), updating (Zsh plugin managers can easily update) and&lt;br&gt;
integrating with &lt;code&gt;git&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Other plugin managers
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Zplug
&lt;/h4&gt;



&lt;pre class="highlight shell"&gt;&lt;code&gt;zplug &lt;span class="s2"&gt;"z-shell/zsh-diff-so-fancy"&lt;/span&gt;, as:command, use:&lt;span class="s2"&gt;"bin/"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;



&lt;h4&gt;
  
  
  Zgen
&lt;/h4&gt;



&lt;pre class="highlight shell"&gt;&lt;code&gt;zgen load z-shell/zsh-diff-so-fancy
&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;Without &lt;code&gt;as"program"&lt;/code&gt;-like functionality the &lt;code&gt;.plugin.zsh&lt;/code&gt; file picks up setup and simulates adding a command to system, so &lt;code&gt;Zgen&lt;/code&gt; and other can work.&lt;/p&gt;




&lt;p&gt;&lt;a href="https://twitter.com/zshell_zi" rel="noopener noreferrer"&gt;@zshell_zi&lt;/a&gt;, &lt;a href="https://z.digitalclouds.dev" rel="noopener noreferrer"&gt;z.digitalclouds.dev&lt;/a&gt;&lt;/p&gt;

</description>
      <category>zsh</category>
      <category>github</category>
      <category>tooling</category>
      <category>shell</category>
    </item>
  </channel>
</rss>
