<?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>Forem: Linwei</title>
    <description>The latest articles on Forem by Linwei (@skywind3000).</description>
    <link>https://forem.com/skywind3000</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%2F55925%2Fc2311f81-2fd8-49c2-bba4-13a6cabedfd4.jpeg</url>
      <title>Forem: Linwei</title>
      <link>https://forem.com/skywind3000</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/skywind3000"/>
    <language>en</language>
    <item>
      <title>Can't believe I've created 20 vim plugins since 2016</title>
      <dc:creator>Linwei</dc:creator>
      <pubDate>Tue, 22 Oct 2024 10:00:29 +0000</pubDate>
      <link>https://forem.com/skywind3000/cant-believe-ive-created-20-vim-plugins-since-2016-4aip</link>
      <guid>https://forem.com/skywind3000/cant-believe-ive-created-20-vim-plugins-since-2016-4aip</guid>
      <description>&lt;p&gt;Maybe you'll be interested in some of them:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/skywind3000/asyncrun.vim" rel="noopener noreferrer"&gt;asyncrun&lt;/a&gt; - 🚀 Run Async Shell Commands in Vim 8.0 and NVim and Output to the Quickfix Window !!&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/skywind3000/asynctasks.vim" rel="noopener noreferrer"&gt;asynctasks&lt;/a&gt; - 🚀 Modern Task System for Project Building, Testing and Deploying !! &lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/skywind3000/gutentags_plus" rel="noopener noreferrer"&gt;gutentags_plus&lt;/a&gt; - The right way to use gtags with gutentags &lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/skywind3000/LeaderF-snippet" rel="noopener noreferrer"&gt;Leaderf-snippets&lt;/a&gt; - Intuitive way to use snippets&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/skywind3000/vim-auto-popmenu" rel="noopener noreferrer"&gt;vim-auto-popmenu&lt;/a&gt; - 😎 Display the Completion Menu Automantically !! &lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/skywind3000/vim-color-export" rel="noopener noreferrer"&gt;vim-color-export&lt;/a&gt; - 🌈 A tool to backport NeoVim colorschemes to Vim !! &lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/skywind3000/vim-color-patch" rel="noopener noreferrer"&gt;vim-color-patch&lt;/a&gt; - 🌈 Load colorscheme patch script automatically !! &lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/skywind3000/vim-cppman" rel="noopener noreferrer"&gt;vim-cppman&lt;/a&gt; - Read Cppman/Man pages right inside your vim. &lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/skywind3000/vim-dict" rel="noopener noreferrer"&gt;vim-dict&lt;/a&gt; - Automatically add dictionary files to current buf according to filetype.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/skywind3000/vim-gpt-commit" rel="noopener noreferrer"&gt;vim-gpt-commit&lt;/a&gt; - 🚀 Generate git commit message using ChatGPT/Ollama !! &lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/skywind3000/vim-gutentags" rel="noopener noreferrer"&gt;vim-gutentags&lt;/a&gt; - manages your ctags/gtag files automatically.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/skywind3000/vim-init" rel="noopener noreferrer"&gt;vim-init&lt;/a&gt; - vimrc tutorials and startup framework.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/skywind3000/vim-keysound" rel="noopener noreferrer"&gt;vim-keysound&lt;/a&gt; - 🍷 Play typewriter sound in Vim when you are typing a letter &lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/skywind3000/vim-navigator" rel="noopener noreferrer"&gt;vim-navigator&lt;/a&gt; - 🚀 Navigate Your Commands Easily !! &lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/skywind3000/vim-preview" rel="noopener noreferrer"&gt;vim-preview&lt;/a&gt; - The missing preview window for vim &lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/skywind3000/quickmenu.vim" rel="noopener noreferrer"&gt;vim-quickmenu&lt;/a&gt; - A nice customizable popup menu for vim &lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/skywind3000/vim-quickui" rel="noopener noreferrer"&gt;vim-quickui&lt;/a&gt; - The missing UI extensions for Vim 9 (and NeoVim) !! 😎 &lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/skywind3000/vim-rt-format" rel="noopener noreferrer"&gt;vim-rt-format&lt;/a&gt; - 😎 Prettify Current Line on Enter !! &lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/skywind3000/vim-terminal-help" rel="noopener noreferrer"&gt;vim-terminal-help&lt;/a&gt; - Small changes make vim/nvim's internal terminal great again.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/skywind3000/vim-text-process" rel="noopener noreferrer"&gt;vim-text-process&lt;/a&gt; - Text Filter Manager for Vim !!&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>vim</category>
      <category>bash</category>
      <category>linux</category>
      <category>neovim</category>
    </item>
    <item>
      <title>What's New Since Vim 9.0?</title>
      <dc:creator>Linwei</dc:creator>
      <pubDate>Wed, 24 Jul 2024 09:54:37 +0000</pubDate>
      <link>https://forem.com/skywind3000/whats-new-since-vim-90-5425</link>
      <guid>https://forem.com/skywind3000/whats-new-since-vim-90-5425</guid>
      <description>&lt;p&gt;Since the release of version 9.0.0, Vim has introduced many exciting new features, such as Vim9 classes/interfaces and virtual text, which have significantly enhanced the overall user experience.&lt;/p&gt;

&lt;p&gt;Here is a comprehensive list of new features introduced since Vim 9.0:&lt;/p&gt;

&lt;h2&gt;
  
  
  Vim 9.1
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;9.1.0572: new &lt;code&gt;tabclose&lt;/code&gt; option to specify tab page closing behaviour.&lt;/li&gt;
&lt;li&gt;9.1.0548: &lt;code&gt;id()&lt;/code&gt; function&lt;/li&gt;
&lt;li&gt;9.1.0509: &lt;code&gt;bindtextdomain()&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;9.1.0507: &lt;code&gt;CursorMovedC&lt;/code&gt; event to monitor cursor movement in command mode.&lt;/li&gt;
&lt;li&gt;9.1.0500: &lt;code&gt;popup_setbuf()&lt;/code&gt; to switch buffer in a popup.&lt;/li&gt;
&lt;li&gt;9.1.0476: new highlighting groups: &lt;code&gt;PmenuMatch&lt;/code&gt; and &lt;code&gt;PmenuMatchSel&lt;/code&gt; to see matched text in popup menu.&lt;/li&gt;
&lt;li&gt;9.1.0469: make &lt;code&gt;completeopt&lt;/code&gt; to have buffer-local value&lt;/li&gt;
&lt;li&gt;9.1.0465: &lt;code&gt;copyfile()&lt;/code&gt;  to copy file.&lt;/li&gt;
&lt;li&gt;9.1.0439: new &lt;code&gt;:filter :history&lt;/code&gt; to filter the history.&lt;/li&gt;
&lt;li&gt;9.1.0394: &lt;code&gt;getregionpos()&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;9.1.0393: support &lt;code&gt;$XDG_CONFIG_HOME&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;9.1.0147: new &lt;code&gt;winfixbuf&lt;/code&gt; option to prevent buffer switching in one window.&lt;/li&gt;
&lt;li&gt;9.1.0120: &lt;code&gt;getregion()&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;9.1.0071: &lt;code&gt;diff()&lt;/code&gt; to compare lists or strings.&lt;/li&gt;
&lt;li&gt;9.1.0059: &lt;code&gt;WinNewPre&lt;/code&gt; event before creating a window.&lt;/li&gt;
&lt;li&gt;9.1.0058: new &lt;code&gt;:map-cmd-key&lt;/code&gt;, try &lt;code&gt;:imap &amp;lt;D-b&amp;gt; bar&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;9.1.0027: &lt;code&gt;foreach()&lt;/code&gt; function&lt;/li&gt;
&lt;li&gt;9.1.0010: keymap completion&lt;/li&gt;
&lt;li&gt;9.1.0009: new &lt;code&gt;matchstrlist()&lt;/code&gt; and &lt;code&gt;matchbufline()&lt;/code&gt; functions.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Vim 9.0
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;9.0.2183: new "maxfuncdepth" option&lt;/li&gt;
&lt;li&gt;9.0.1950: &lt;code&gt;new()&lt;/code&gt; function&lt;/li&gt;
&lt;li&gt;9.0.1786: &lt;code&gt;instanceof()&lt;/code&gt; function&lt;/li&gt;
&lt;li&gt;9.0.1777: new &lt;code&gt;v:python3_version&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;9.0.1776: python3-stable-api&lt;/li&gt;
&lt;li&gt;9.0.1704: can use positional arguments for &lt;code&gt;printf()&lt;/code&gt; .&lt;/li&gt;
&lt;li&gt;9.0.1485: &lt;code&gt;strutf16len()&lt;/code&gt; and &lt;code&gt;utf16idx()&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;9.0.1276: new ":map-meta-keys", try &lt;code&gt;imap &amp;lt;T-b&amp;gt; terrible&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;9.0.1212: new &lt;code&gt;getcellwidths()&lt;/code&gt; function.&lt;/li&gt;
&lt;li&gt;9.0.1122: new &lt;code&gt;:autocmd-block&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;9.0.1031: vim9 class/interface.&lt;/li&gt;
&lt;li&gt;9.0.1007: &lt;code&gt;swapfilelist()&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;9.0.0819: new &lt;code&gt;endofline&lt;/code&gt; and &lt;code&gt;endoffile&lt;/code&gt; option&lt;/li&gt;
&lt;li&gt;9.0.0881: new &lt;code&gt;getmouseshape()&lt;/code&gt; function&lt;/li&gt;
&lt;li&gt;9.0.0916: new &lt;code&gt;getbufoneline()&lt;/code&gt; function.&lt;/li&gt;
&lt;li&gt;9.0.0683: &lt;code&gt;popup_findecho()&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;9.0.0647: new &lt;code&gt;splitkeep&lt;/code&gt; option&lt;/li&gt;
&lt;li&gt;9.0.0640: smoothscroll&lt;/li&gt;
&lt;li&gt;9.0.0496: drop Windows-XP support. (PR #11089)&lt;/li&gt;
&lt;li&gt;9.0.0449: &lt;code&gt;keytrans()&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;9.0.0370: new ":defer" command to call function when current function is done.&lt;/li&gt;
&lt;li&gt;9.0.0321: new ":echow" command to display message in a popup window.&lt;/li&gt;
&lt;li&gt;9.0.0285: &lt;code&gt;setcmdline()&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;9.0.0244: &lt;code&gt;getscriptinfo()&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;9.0.0196: &lt;code&gt;indexof()&lt;/code&gt; function to search item in list/string&lt;/li&gt;
&lt;li&gt;9.0.0067: virtual-text&lt;/li&gt;
&lt;li&gt;9.0.0009: &lt;code&gt;matchbufline()&lt;/code&gt; and &lt;code&gt;matchstrlist()&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;9.0.0007: terminal support for double, dotted and dashed underlines&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>vim</category>
      <category>linux</category>
    </item>
    <item>
      <title>Why does the indexing of array start with ZERO in C?</title>
      <dc:creator>Linwei</dc:creator>
      <pubDate>Tue, 08 Aug 2023 07:55:11 +0000</pubDate>
      <link>https://forem.com/skywind3000/why-does-the-indexing-of-array-start-with-zero-in-c-4djh</link>
      <guid>https://forem.com/skywind3000/why-does-the-indexing-of-array-start-with-zero-in-c-4djh</guid>
      <description>&lt;p&gt;Most programming languages today, including C, use a zero-based index for arrays due to some compelling reasons.&lt;/p&gt;

&lt;h2&gt;
  
  
  Better addressing
&lt;/h2&gt;

&lt;p&gt;If a C language array starts from 0, the address of array[i] would be exactly:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(array + i)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;which is very consistent. But if it starts from 1, the address of array[i] would be:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(array + i - 1)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;One more computation would affect the performance, and it would be even worse if extended to a two-dimensional array.&lt;/p&gt;

&lt;p&gt;For ZERO-based indexing, the address of &lt;code&gt;array[i][j]&lt;/code&gt; is&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(array + i * N + j)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;which is very neat. But for 1-based indexing, the address of &lt;code&gt;array[i][j]&lt;/code&gt; will become:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(array + (i - 1) * N + (j - 1))
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;It would be more cumbersome. Additionally, if we start with 1, the same address cannot be addressed uniformly using "pointer + offset" and "array + index", and conversion is often required. So, why bother?&lt;/p&gt;

&lt;h2&gt;
  
  
  Computer hardware is designed to use 0 as the starting index
&lt;/h2&gt;

&lt;p&gt;Physical memory addressing and port addressing both start from 0. For example, the address range of a 32-bit computer's memory is:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[0, 2 ^ 32 - 1]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;which can be represented by a 32-bit integer. However, if the memory is addressed starting from 1, then the address range of a 32-bit computer becomes:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[1, 2 ^ 32]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;In that case, the highest address 2 ^ 32 would require a 33-bit integer, which would be a waste of resources.&lt;/p&gt;

&lt;p&gt;Other port addresses and DMA channels also follow this starting from 0 principle. If we use 3 bits to represent DMA channels, it is better to express 8 channels (0-7), while starting from 1, the same 3 bits can only express 7 channels (1-7), which is also a waste of resources.&lt;/p&gt;

&lt;p&gt;Therefore, a language that is close to the system naturally chooses to follow the hardware settings. In addition to the simpler addressing calculation mentioned in the first point, it can also maintain consistency with the computer system and unify the user experience of pointer addressing and array addressing.&lt;/p&gt;

&lt;p&gt;Dijkstra explained that the reason programming languages do this is simply to follow hardware design decisions:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The decision taken by the language specification &amp;amp; compiler-designers is based on the decision made by computer system-designers to start count at 0.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Therefore, C language arrays start at zero for the following reasons: 1) Better performance; 2) Unified array and pointer addressing; 3) Following hardware addressing conventions.&lt;/p&gt;

&lt;p&gt;In addition to these practical reasons, there are also some theoretical reasons.&lt;/p&gt;

&lt;h2&gt;
  
  
  Theoretical reasons
&lt;/h2&gt;

&lt;p&gt;Apart from array indexing, Dijkstra advocated that all counting should start from 0, and he wrote an article to explain this viewpoint:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.cs.utexas.edu/users/EWD/ewd08xx/EWD831.PDF"&gt;https://www.cs.utexas.edu/users/EWD/ewd08xx/EWD831.PDF&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;He explicitly criticized early languages like Fortran and Pascal that started from 1 for not considering enough:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--2WM_f3lh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rt49vh0r0pwyx3zq2awn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--2WM_f3lh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rt49vh0r0pwyx3zq2awn.png" alt="Image description" width="800" height="415"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;He gave an impeccable reason, probably arguing that there are several ways to express the integer sequence 2, 3, 4, ..., 12.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;a）2 &amp;lt;= i &amp;lt; 13
b）1 &amp;lt; i &amp;lt;= 12
c）2 &amp;lt;= i &amp;lt;= 12
d）1 &amp;lt; i &amp;lt; 13
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then he explained:&lt;/p&gt;

&lt;p&gt;For the left side, the expression "a &amp;lt;= x" is better than "a &amp;lt; x" because if "a &amp;lt; x" is used to express a sequence, you always need to provide a number that is smaller than the first element, which is not only annoying but also often impossible (there exists a smallest rational number, but there is no largest rational number). Therefore, "a &amp;lt;= x" is a better expression.&lt;/p&gt;

&lt;p&gt;For the right side, the expression "x &amp;lt; b" is better than "x &amp;lt;= b" because when a = b, "a &amp;lt;= x &amp;lt; b" can represent an empty set while "a &amp;lt;= x &amp;lt;= b" cannot represent an empty set.&lt;/p&gt;

&lt;p&gt;Both scheme (a) and scheme (b) can easily show the length of the sequence.&lt;/p&gt;

&lt;p&gt;Scheme (a) and scheme (d) are easier to express adjacent sequences.&lt;/p&gt;

&lt;p&gt;Thus, it was proved that the left-closed and right-open scheme (a) "a &amp;lt;= x &amp;lt; b" is more suitable for expressing a sequence.&lt;/p&gt;

&lt;p&gt;After Dijkstra argued that "a &amp;lt;= x &amp;lt; b" is a better choice, he concluded that an array of length N should start from 0, because the expression "0 &amp;lt;= x &amp;lt; N" is clearer than "1 &amp;lt;= x &amp;lt; N+1".&lt;/p&gt;

</description>
      <category>c</category>
      <category>programming</category>
      <category>linux</category>
      <category>cpp</category>
    </item>
    <item>
      <title>Benchmark asyncio vs gevent vs native epoll</title>
      <dc:creator>Linwei</dc:creator>
      <pubDate>Tue, 13 Dec 2022 12:49:49 +0000</pubDate>
      <link>https://forem.com/skywind3000/performance-asyncio-vs-gevent-vs-native-epoll-bnl</link>
      <guid>https://forem.com/skywind3000/performance-asyncio-vs-gevent-vs-native-epoll-bnl</guid>
      <description>&lt;p&gt;Everyone knows the &lt;code&gt;asyncio&lt;/code&gt; module in python schedules all coroutines in a single thread. That means it helps you code easier, and you can't gain any performance from it.&lt;/p&gt;

&lt;p&gt;But what is the performance of python's &lt;code&gt;asyncio&lt;/code&gt; module? How fast can it run compared to traditional &lt;code&gt;gevent&lt;/code&gt; and native &lt;code&gt;epoll&lt;/code&gt; ?&lt;/p&gt;

&lt;h2&gt;
  
  
  Requirements
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip3 &lt;span class="nb"&gt;install &lt;/span&gt;hiredis gevent
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;An optional package &lt;a href="https://github.com/MagicStack/uvloop"&gt;uvloop&lt;/a&gt; can also be install if working on Linux:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip3 &lt;span class="nb"&gt;install &lt;/span&gt;uvloop
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Source
&lt;/h2&gt;

&lt;p&gt;The following code uses both &lt;code&gt;asyncio&lt;/code&gt; and &lt;code&gt;gevent&lt;/code&gt; to simulate a redis server on port 5000, 5001, and 5002.&lt;/p&gt;

&lt;p&gt;They can be tested with &lt;code&gt;redis-benchmark&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;content of &lt;code&gt;echo_bench_gevent.py&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;sys&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;gevent&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;gevent.monkey&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;hiredis&lt;/span&gt;

&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;gevent.server&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;StreamServer&lt;/span&gt;
&lt;span class="n"&gt;gevent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;monkey&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;patch_all&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="n"&gt;d&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;process&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="c1"&gt;# only support get/set
&lt;/span&gt;    &lt;span class="n"&gt;cmd&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;lower&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;cmd&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sa"&gt;b&lt;/span&gt;&lt;span class="s"&gt;'set'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sa"&gt;b&lt;/span&gt;&lt;span class="s"&gt;"+OK&lt;/span&gt;&lt;span class="se"&gt;\r\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;cmd&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sa"&gt;b&lt;/span&gt;&lt;span class="s"&gt;'get'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sa"&gt;b&lt;/span&gt;&lt;span class="s"&gt;'$-1&lt;/span&gt;&lt;span class="se"&gt;\r\n&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sa"&gt;b&lt;/span&gt;&lt;span class="s"&gt;'$1&lt;/span&gt;&lt;span class="se"&gt;\r\n&lt;/span&gt;&lt;span class="s"&gt;1&lt;/span&gt;&lt;span class="se"&gt;\r\n&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cmd&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nb"&gt;NotImplementedError&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sa"&gt;b&lt;/span&gt;&lt;span class="s"&gt;''&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;handle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sock&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;addr&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;reader&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;hiredis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Reader&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;buf&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sock&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;recv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;4096&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt;
        &lt;span class="n"&gt;reader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;feed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;req&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;reader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;gets&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="k"&gt;break&lt;/span&gt;
            &lt;span class="n"&gt;sock&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sendall&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;process&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;

&lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'serving on 0.0.0.0:5000'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;server&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;StreamServer&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="s"&gt;'0.0.0.0'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5000&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;handle&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;serve_forever&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;content of &lt;code&gt;echo_bench_asyncio.py&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;asyncio&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;hiredis&lt;/span&gt;

&lt;span class="n"&gt;d&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;process&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;cmd&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;lower&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;cmd&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sa"&gt;b&lt;/span&gt;&lt;span class="s"&gt;'set'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sa"&gt;b&lt;/span&gt;&lt;span class="s"&gt;"+OK&lt;/span&gt;&lt;span class="se"&gt;\r\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;cmd&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sa"&gt;b&lt;/span&gt;&lt;span class="s"&gt;'get'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sa"&gt;b&lt;/span&gt;&lt;span class="s"&gt;'$-1&lt;/span&gt;&lt;span class="se"&gt;\r\n&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sa"&gt;b&lt;/span&gt;&lt;span class="s"&gt;'$1&lt;/span&gt;&lt;span class="se"&gt;\r\n&lt;/span&gt;&lt;span class="s"&gt;1&lt;/span&gt;&lt;span class="se"&gt;\r\n&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;
    &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;cmd&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sa"&gt;b&lt;/span&gt;&lt;span class="s"&gt;'config'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sa"&gt;b&lt;/span&gt;&lt;span class="s"&gt;'-ERROR&lt;/span&gt;&lt;span class="se"&gt;\r\n&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sa"&gt;b&lt;/span&gt;&lt;span class="s"&gt;'-ERROR&lt;/span&gt;&lt;span class="se"&gt;\r\n&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sa"&gt;b&lt;/span&gt;&lt;span class="s"&gt;''&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;echo_server&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;reader&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;writer&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;hireader&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;hiredis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Reader&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;reader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;read&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;4096&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;break&lt;/span&gt;
        &lt;span class="n"&gt;hireader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;feed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;req&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;hireader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;gets&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="k"&gt;break&lt;/span&gt;
            &lt;span class="n"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;process&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;writer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;writer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;drain&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;server&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;asyncio&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;start_server&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;echo_server&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'0.0.0.0'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5001&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'serving on {}'&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sockets&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;getsockname&lt;/span&gt;&lt;span class="p"&gt;()))&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;serve_forever&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;

&lt;span class="n"&gt;asyncio&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;content of &lt;code&gt;echo_bench_asyncio_uvloop.py&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;asyncio&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;hiredis&lt;/span&gt;

&lt;span class="n"&gt;d&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;process&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;cmd&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;lower&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;cmd&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sa"&gt;b&lt;/span&gt;&lt;span class="s"&gt;'set'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sa"&gt;b&lt;/span&gt;&lt;span class="s"&gt;"+OK&lt;/span&gt;&lt;span class="se"&gt;\r\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;cmd&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sa"&gt;b&lt;/span&gt;&lt;span class="s"&gt;'get'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sa"&gt;b&lt;/span&gt;&lt;span class="s"&gt;'$-1&lt;/span&gt;&lt;span class="se"&gt;\r\n&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sa"&gt;b&lt;/span&gt;&lt;span class="s"&gt;'$1&lt;/span&gt;&lt;span class="se"&gt;\r\n&lt;/span&gt;&lt;span class="s"&gt;1&lt;/span&gt;&lt;span class="se"&gt;\r\n&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;
    &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;cmd&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sa"&gt;b&lt;/span&gt;&lt;span class="s"&gt;'config'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sa"&gt;b&lt;/span&gt;&lt;span class="s"&gt;'-ERROR&lt;/span&gt;&lt;span class="se"&gt;\r\n&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sa"&gt;b&lt;/span&gt;&lt;span class="s"&gt;'-ERROR&lt;/span&gt;&lt;span class="se"&gt;\r\n&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sa"&gt;b&lt;/span&gt;&lt;span class="s"&gt;''&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;echo_server&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;reader&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;writer&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;hireader&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;hiredis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Reader&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;reader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;read&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;4096&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;break&lt;/span&gt;
        &lt;span class="n"&gt;hireader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;feed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;req&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;hireader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;gets&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="k"&gt;break&lt;/span&gt;
            &lt;span class="n"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;process&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;writer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;writer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;drain&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;server&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;asyncio&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;start_server&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;echo_server&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'0.0.0.0'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5002&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'serving on {}'&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sockets&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;getsockname&lt;/span&gt;&lt;span class="p"&gt;()))&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;serve_forever&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;

&lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;uvloop&lt;/span&gt;
    &lt;span class="n"&gt;uvloop&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;install&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'uvloop is enabled'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="nb"&gt;ImportError&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'uvloop is not available'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;asyncio&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Start servers
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python3 echo_bench_gevent.py          &lt;span class="c"&gt;# will listen on port 5000&lt;/span&gt;
python3 echo_bench_asyncio.py         &lt;span class="c"&gt;# will listen on port 5001&lt;/span&gt;
python3 echo_bench_asyncio_uvloop.py  &lt;span class="c"&gt;# will listen on port 5002&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Test
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;redis-benchmark &lt;span class="nt"&gt;-p&lt;/span&gt; 5000 &lt;span class="nt"&gt;-t&lt;/span&gt; get &lt;span class="nt"&gt;-n&lt;/span&gt; 100000 &lt;span class="nt"&gt;-r&lt;/span&gt; 100000000
redis-benchmark &lt;span class="nt"&gt;-p&lt;/span&gt; 5001 &lt;span class="nt"&gt;-t&lt;/span&gt; get &lt;span class="nt"&gt;-n&lt;/span&gt; 100000 &lt;span class="nt"&gt;-r&lt;/span&gt; 100000000
redis-benchmark &lt;span class="nt"&gt;-p&lt;/span&gt; 5002 &lt;span class="nt"&gt;-t&lt;/span&gt; get &lt;span class="nt"&gt;-n&lt;/span&gt; 100000 &lt;span class="nt"&gt;-r&lt;/span&gt; 100000000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Result
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Mode&lt;/th&gt;
&lt;th&gt;Python 3.9&lt;/th&gt;
&lt;th&gt;Python 3.11&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;gevent&lt;/td&gt;
&lt;td&gt;34281.80 requests / second&lt;/td&gt;
&lt;td&gt;32258.07 requests / second&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;asyncio&lt;/td&gt;
&lt;td&gt;40144.52 requests / second&lt;/td&gt;
&lt;td&gt;51652.89 requests / second&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;asyncio + uvloop&lt;/td&gt;
&lt;td&gt;64102.57 requests / second&lt;/td&gt;
&lt;td&gt;66577.90 requests / second&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Native epoll
&lt;/h2&gt;

&lt;p&gt;Redis is implemented with &lt;code&gt;epoll&lt;/code&gt; in C, and we can test redis directly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;redis-benchmark &lt;span class="nt"&gt;-p&lt;/span&gt; 6379 &lt;span class="nt"&gt;-t&lt;/span&gt; get &lt;span class="nt"&gt;-n&lt;/span&gt; 100000 &lt;span class="nt"&gt;-r&lt;/span&gt; 100000000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;75244.55 requests per second
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;asyncio&lt;/code&gt; is 50% faster than &lt;code&gt;gevent&lt;/code&gt; in Python 3.11&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;asyncio&lt;/code&gt; can run twice as fast as &lt;code&gt;gevent&lt;/code&gt; with &lt;code&gt;uvloop&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;asyncio&lt;/code&gt; can go up to 68% of a native epoll program.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;asyncio&lt;/code&gt; can go up to 88% of a native epoll program with &lt;code&gt;uvloop&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>python</category>
      <category>asyncio</category>
    </item>
    <item>
      <title>asyncrun.vim: run commands in iterm2, tmux, or gnome/kde terminal</title>
      <dc:creator>Linwei</dc:creator>
      <pubDate>Tue, 04 Jan 2022 19:08:56 +0000</pubDate>
      <link>https://forem.com/skywind3000/asyncrunvim-run-commands-in-iterm2-tmux-or-gnomekde-terminal-2l91</link>
      <guid>https://forem.com/skywind3000/asyncrunvim-run-commands-in-iterm2-tmux-or-gnomekde-terminal-2l91</guid>
      <description>&lt;p&gt;&lt;a href="https://github.com/skywind3000/asyncrun.vim" rel="noopener noreferrer"&gt;asyncrun.vim&lt;/a&gt; was known as a shell command runner in the quickfix window. However, it first got released six years ago (2016), when the &lt;code&gt;+job&lt;/code&gt; feature just became stable in vim &lt;code&gt;7.4.1829&lt;/code&gt;. During these years, numerous issues have been addressed, and valuable feedbacks got collected.&lt;/p&gt;

&lt;p&gt;At the beginning of 2022, I'd like to share some recent changes which may be helpful to improve your productivity.&lt;/p&gt;

&lt;h2&gt;
  
  
  New runners
&lt;/h2&gt;

&lt;p&gt;Both Vim and NeoVim got &lt;code&gt;+terminal&lt;/code&gt; features for years, but some people still used to run new jobs in system terminals, like gnome-terminal, xfce-terminal, iterm2, or konsole. &lt;/p&gt;

&lt;p&gt;With the power of &lt;a href="https://github.com/skywind3000/asyncrun.vim/wiki/Customize-Runner" rel="noopener noreferrer"&gt;user-defined runners&lt;/a&gt;, you can run commands anywhere you want instead of in the quickfix window. Some pre-included runners can be used to interact with those external system terminals: &lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Runner&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;th&gt;Requirement&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;gnome&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;in a new gnome terminal&lt;/td&gt;
&lt;td&gt;GNOME&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;gnome_tab&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;in a new gnome terminal tab&lt;/td&gt;
&lt;td&gt;GNOME&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;xterm&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;in a xterm window&lt;/td&gt;
&lt;td&gt;xterm&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;tmux&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;in another tmux split&lt;/td&gt;
&lt;td&gt;&lt;a href="https://github.com/preservim/vimux" rel="noopener noreferrer"&gt;Vimux&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;xfce&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;in a new xfce terminal&lt;/td&gt;
&lt;td&gt;xfce4-terminal&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;konsole&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;in a new konsole terminal&lt;/td&gt;
&lt;td&gt;KDE&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;macos&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;in a macOS system terminal&lt;/td&gt;
&lt;td&gt;macOS&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;iterm&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;in a new iterm2 tab&lt;/td&gt;
&lt;td&gt;macOS + iTerm2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;external&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;in a new cmd.exe window&lt;/td&gt;
&lt;td&gt;Windows&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;When using asyncrun with &lt;code&gt;-mode=term&lt;/code&gt;, you can provide an option &lt;code&gt;-pos={runner}&lt;/code&gt; to specify runner name:&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="p"&gt;:&lt;/span&gt;AsyncRun &lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="k"&gt;mode&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;term&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt;pos&lt;span class="p"&gt;=&lt;/span&gt;gnome      &lt;span class="k"&gt;ls&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="k"&gt;la&lt;/span&gt;
&lt;span class="p"&gt;:&lt;/span&gt;AsyncRun &lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="k"&gt;mode&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;term&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt;pos&lt;span class="p"&gt;=&lt;/span&gt;floaterm   &lt;span class="k"&gt;ls&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="k"&gt;la&lt;/span&gt;
&lt;span class="p"&gt;:&lt;/span&gt;AsyncRun &lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="k"&gt;mode&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;term&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt;pos&lt;span class="p"&gt;=&lt;/span&gt;tmux       &lt;span class="k"&gt;ls&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="k"&gt;la&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When using &lt;code&gt;gnome&lt;/code&gt;, &lt;code&gt;konsole&lt;/code&gt;, &lt;code&gt;external&lt;/code&gt;, or &lt;code&gt;xfce&lt;/code&gt; runner in GVim, you can get exactly the same experience like starting a command-line program from IDEs:&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%2Fraw.githubusercontent.com%2Fskywind3000%2Fimages%2Fmaster%2Fp%2Fasyncrun%2Frunner-gnome2.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%2Fraw.githubusercontent.com%2Fskywind3000%2Fimages%2Fmaster%2Fp%2Fasyncrun%2Frunner-gnome2.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you are using terminal vim, a new gnome-terminal tab, or iterm2 tab may be a good start:&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%2Fskywind3000%2Fimages%2Fraw%2Fmaster%2Fp%2Fasyncrun_extra%2Fp_gnome_tab.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%2Fskywind3000%2Fimages%2Fraw%2Fmaster%2Fp%2Fasyncrun_extra%2Fp_gnome_tab.gif"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;or perhaps in a tmux split:&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%2Fskywind3000%2Fimages%2Fraw%2Fmaster%2Fp%2Fasyncrun_extra%2Fp_tmux.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%2Fskywind3000%2Fimages%2Fraw%2Fmaster%2Fp%2Fasyncrun_extra%2Fp_tmux.gif"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Besides the system terminal, there are also runners for some most  famous internal terminal plugins:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Runner&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;th&gt;Requirement&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;floaterm&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;in a new floaterm window&lt;/td&gt;
&lt;td&gt;&lt;a href="https://github.com/voldikss/vim-floaterm" rel="noopener noreferrer"&gt;floaterm&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;floaterm_reuse&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;in a reusable floaterm window&lt;/td&gt;
&lt;td&gt;&lt;a href="https://github.com/voldikss/vim-floaterm" rel="noopener noreferrer"&gt;floaterm&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;quickui&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;in a quickui window&lt;/td&gt;
&lt;td&gt;&lt;a href="https://github.com/skywind3000/vim-quickui" rel="noopener noreferrer"&gt;vim-quickui&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;toggleterm&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;in a toggleterm window&lt;/td&gt;
&lt;td&gt;&lt;a href="https://github.com/akinsho/toggleterm.nvim" rel="noopener noreferrer"&gt;toggleterm.nvim&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;termhelp&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;in terminal help&lt;/td&gt;
&lt;td&gt;&lt;a href="https://github.com/skywind3000/vim-terminal-help" rel="noopener noreferrer"&gt;vim-terminal-help&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Screenshot for the &lt;code&gt;floaterm&lt;/code&gt; runner:&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%2Fskywind3000%2Fimages%2Fraw%2Fmaster%2Fp%2Fasyncrun_extra%2Fp_floaterm.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%2Fskywind3000%2Fimages%2Fraw%2Fmaster%2Fp%2Fasyncrun_extra%2Fp_floaterm.gif"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Terminal-help:&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%2Fskywind3000%2Fimages%2Fraw%2Fmaster%2Fp%2Fasyncrun_extra%2Fp_help.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%2Fskywind3000%2Fimages%2Fraw%2Fmaster%2Fp%2Fasyncrun_extra%2Fp_help.gif"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;All runners are customizable, you can modify or define your own runners, see the &lt;a href="https://github.com/skywind3000/asyncrun.vim/wiki/Customize-Runner" rel="noopener noreferrer"&gt;customize runner&lt;/a&gt; page.&lt;/p&gt;

&lt;h2&gt;
  
  
  Internal terminal
&lt;/h2&gt;

&lt;p&gt;Another exciting feature is interacting with (neo)vim's internal terminal:&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 command in the internal-terminal in a new tab &lt;/span&gt;
&lt;span class="p"&gt;:&lt;/span&gt;AsyncRun &lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="k"&gt;mode&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;term&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt;pos&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="k"&gt;tab&lt;/span&gt;    &lt;span class="k"&gt;ls&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="k"&gt;la&lt;/span&gt;
&lt;span class="p"&gt;:&lt;/span&gt;AsyncRun &lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="k"&gt;mode&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;term&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt;pos&lt;span class="p"&gt;=&lt;/span&gt;TAB    &lt;span class="k"&gt;ls&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="k"&gt;la&lt;/span&gt;

&lt;span class="c"&gt;" open on the left/right/top/bottom side&lt;/span&gt;
&lt;span class="p"&gt;:&lt;/span&gt;AsyncRun &lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="k"&gt;mode&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;term&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt;pos&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="k"&gt;left&lt;/span&gt;   &lt;span class="k"&gt;ls&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="k"&gt;la&lt;/span&gt;
&lt;span class="p"&gt;:&lt;/span&gt;AsyncRun &lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="k"&gt;mode&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;term&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt;pos&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="k"&gt;right&lt;/span&gt;  &lt;span class="k"&gt;ls&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="k"&gt;la&lt;/span&gt;
&lt;span class="p"&gt;:&lt;/span&gt;AsyncRun &lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="k"&gt;mode&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;term&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt;pos&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;top&lt;/span&gt;    &lt;span class="k"&gt;ls&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="k"&gt;la&lt;/span&gt;
&lt;span class="p"&gt;:&lt;/span&gt;AsyncRun &lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="k"&gt;mode&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;term&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt;pos&lt;span class="p"&gt;=&lt;/span&gt;bottom &lt;span class="k"&gt;ls&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="k"&gt;la&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You may ask that you can directly use the builtin &lt;code&gt;:term xxx&lt;/code&gt; command to start the internal terminal, what is the difference to use &lt;code&gt;:AsyncRun&lt;/code&gt; for this ?&lt;/p&gt;

&lt;p&gt;The main reasons are convenience and flexibility:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Macros like &lt;code&gt;$(VIM_FILENAME)&lt;/code&gt; or &lt;code&gt;$(VIM_ROOT)&lt;/code&gt; can be expanded in the command:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight viml"&gt;&lt;code&gt;&lt;span class="p"&gt;:&lt;/span&gt;AsyncRun &lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="k"&gt;mode&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;term&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt;pos&lt;span class="p"&gt;=&lt;/span&gt;TAB  &lt;span class="k"&gt;ls&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="k"&gt;la&lt;/span&gt; $&lt;span class="p"&gt;(&lt;/span&gt;VIM_FILEDIR&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Working directory can be customized by &lt;code&gt;-cwd=&lt;/code&gt; option:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight viml"&gt;&lt;code&gt;&lt;span class="p"&gt;:&lt;/span&gt;AsyncRun &lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="k"&gt;mode&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;term&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt;pos&lt;span class="p"&gt;=&lt;/span&gt;TAB &lt;span class="p"&gt;-&lt;/span&gt;cwd&lt;span class="p"&gt;=~&lt;/span&gt;/github  &lt;span class="k"&gt;ls&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="k"&gt;la&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Easier to specify the opening position and size:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight viml"&gt;&lt;code&gt;&lt;span class="p"&gt;:&lt;/span&gt;AsyncRun &lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="k"&gt;mode&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;term&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt;pos&lt;span class="p"&gt;=&lt;/span&gt;bottom &lt;span class="p"&gt;-&lt;/span&gt;rows&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="m"&gt;8&lt;/span&gt;  &lt;span class="k"&gt;ls&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="k"&gt;la&lt;/span&gt;
&lt;span class="p"&gt;:&lt;/span&gt;AsyncRun &lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="k"&gt;mode&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;term&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt;pos&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="k"&gt;right&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt;cols&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="m"&gt;40&lt;/span&gt;  &lt;span class="k"&gt;ls&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="k"&gt;la&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;No distraction and prevent focus changing by providing &lt;code&gt;-focus=0&lt;/code&gt; option:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight viml"&gt;&lt;code&gt;&lt;span class="p"&gt;:&lt;/span&gt;AsyncRun &lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="k"&gt;mode&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;term&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt;pos&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="k"&gt;tab&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt;focus&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;  &lt;span class="k"&gt;ls&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="k"&gt;la&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Can close the terminal window automatically when job is finished if &lt;code&gt;-close&lt;/code&gt; option presents.&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight viml"&gt;&lt;code&gt;&lt;span class="p"&gt;:&lt;/span&gt;AsyncRun &lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="k"&gt;mode&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;term&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt;pos&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="k"&gt;tab&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt;focus&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="k"&gt;close&lt;/span&gt; &lt;span class="k"&gt;ls&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="k"&gt;la&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Run a vim command when job finished by &lt;code&gt;-post=xxx&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight viml"&gt;&lt;code&gt;&lt;span class="p"&gt;:&lt;/span&gt;AsyncRun &lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="k"&gt;mode&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;term&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt;post&lt;span class="p"&gt;=&lt;/span&gt;echo\ &lt;span class="s1"&gt;'notify'&lt;/span&gt;   &lt;span class="k"&gt;ls&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="k"&gt;la&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

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

&lt;p&gt;And there are some more benefits:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Environment variables like &lt;code&gt;$VIM_FILENAME&lt;/code&gt; can be initialized correctly.&lt;/li&gt;
&lt;li&gt;Prevent listing terminal buffer in the buffer-list by &lt;code&gt;-listed=0&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Set &lt;code&gt;bufhidden&lt;/code&gt; to &lt;code&gt;hide&lt;/code&gt; for terminal buffer by &lt;code&gt;-hidden=1&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Reuse the previous terminal window by &lt;code&gt;-reuse&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Notify can be setup by &lt;code&gt;-post=xxx&lt;/code&gt; option.&lt;/li&gt;
&lt;li&gt;Corresponding experience in both vim and neovim.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The most important thing is that vim/neovim's &lt;code&gt;:term&lt;/code&gt; command can't escape complex strings correctly in Windows or some rare shells when arguments contain white spaces or quotes and bars. AsyncRun can pass arguments precisely as what they are.&lt;/p&gt;

&lt;p&gt;My favorite terminal position is &lt;code&gt;-pos=TAB&lt;/code&gt;, different with lower case &lt;code&gt;-pos=tab&lt;/code&gt;, it will open a new terminal tab on the left side of my current tabpage:&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%2Fraw.githubusercontent.com%2Fskywind3000%2Fimages%2Fmaster%2Fp%2Fasyncrun%2Fmode_term_3.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%2Fraw.githubusercontent.com%2Fskywind3000%2Fimages%2Fmaster%2Fp%2Fasyncrun%2Fmode_term_3.png"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;I use it a lot to execute the current file because when it is finished, the tab will close, and it will return to the previous tabpage where I was working.&lt;/p&gt;

&lt;p&gt;Excluding macro variables substitution, some of the actions above can be achieved by original &lt;code&gt;:term&lt;/code&gt; with one or more other commands. Still, asyncrun provides a unified interface for these trivial things in one command and eliminates the difference between vim and neovim.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;asyncrun.vim provides you with all the possible ways to run commands in vim with no compromise. Feel free to choose the one you like, and don't forget to check the &lt;a href="https://github.com/skywind3000/asyncrun.vim/wiki/Command-Specification" rel="noopener noreferrer"&gt;command specification&lt;/a&gt; for more.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Bonus&lt;/strong&gt;: If you find mapping asyncrun commands for different projects or file-types challenging, you may be benefit from a sibling plugin &lt;a href="https://github.com/skywind3000/asynctasks.vim" rel="noopener noreferrer"&gt;asynctasks.vim&lt;/a&gt;, it uses asyncrun as the backend and introduces vscode like task system in vim.&lt;/p&gt;

&lt;p&gt;.&lt;/p&gt;

</description>
      <category>vim</category>
      <category>linux</category>
      <category>productivity</category>
      <category>terminal</category>
    </item>
    <item>
      <title>Vim 2022: 🍷 Play typewriter sound in Vim when you are typing a letter </title>
      <dc:creator>Linwei</dc:creator>
      <pubDate>Thu, 30 Dec 2021 17:35:18 +0000</pubDate>
      <link>https://forem.com/skywind3000/vim-2022-play-typewriter-sound-in-vim-when-you-are-typing-a-letter-cl3</link>
      <guid>https://forem.com/skywind3000/vim-2022-play-typewriter-sound-in-vim-when-you-are-typing-a-letter-cl3</guid>
      <description>&lt;p&gt;It's cool to play typewriter sound in Vim when you are typing a letter. 😎&lt;/p&gt;

&lt;p&gt;So I made a little [script] for this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight viml"&gt;&lt;code&gt;Plug &lt;span class="s1"&gt;'skywind3000/vim-keysound'&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;g:keysound_enable&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;g:keysound_theme&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'default'&lt;/span&gt;

&lt;span class="c"&gt;" volume range is from 0 to 1000&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;g:keysound_volume&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;500&lt;/span&gt;   
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;apt-get &lt;span class="nb"&gt;install &lt;/span&gt;python3-sdl2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Make sure that your vim has &lt;code&gt;+python3&lt;/code&gt; feature enabled.&lt;/p&gt;

&lt;p&gt;And you go.&lt;/p&gt;

&lt;p&gt;See this video by Keefle (there is no audio delay in reality).&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://streamable.com/yah0h"&gt;https://streamable.com/yah0h&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>vim</category>
      <category>linux</category>
      <category>productivity</category>
    </item>
    <item>
      <title>The world of desktops, laptops will never understand</title>
      <dc:creator>Linwei</dc:creator>
      <pubDate>Sat, 25 Dec 2021 15:14:25 +0000</pubDate>
      <link>https://forem.com/skywind3000/the-world-of-desktops-laptops-will-never-understand--1d6e</link>
      <guid>https://forem.com/skywind3000/the-world-of-desktops-laptops-will-never-understand--1d6e</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--id7UXjqN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/g80m4vns8c9122e1gfpc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--id7UXjqN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/g80m4vns8c9122e1gfpc.png" alt="Image description" width="880" height="623"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;--&lt;/p&gt;

</description>
      <category>linux</category>
      <category>desktop</category>
      <category>laptop</category>
      <category>commandline</category>
    </item>
    <item>
      <title>Study Japanese in the Command Line !</title>
      <dc:creator>Linwei</dc:creator>
      <pubDate>Thu, 23 Dec 2021 18:23:29 +0000</pubDate>
      <link>https://forem.com/skywind3000/study-japanese-in-the-command-line--3p</link>
      <guid>https://forem.com/skywind3000/study-japanese-in-the-command-line--3p</guid>
      <description>&lt;p&gt;Do you want to study Japanese? How many times did you fail in remembering hiragana/katakana? Is there a easy way to master them ?&lt;/p&gt;

&lt;p&gt;Yes, you can learn and practice kanas now in the command line by playing &lt;a href="https://github.com/skywind3000/KanaQuiz"&gt;KanaQuiz&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;List kanas by&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;python3 kanaquiz.py -l
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;You can see hiraganas and katakanas right in your terminal:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--h9Ov0ud3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://github.com/skywind3000/KanaQuiz/blob/master/images/table.png%3Fraw%3Dtrue" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--h9Ov0ud3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://github.com/skywind3000/KanaQuiz/blob/master/images/table.png%3Fraw%3Dtrue" alt="" width="357" height="418"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Start a new quiz by &lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;python3 kanaquiz.py -h
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;After pressing Enter, the quiz proceeds:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--BUFMF31I--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://github.com/skywind3000/KanaQuiz/blob/master/images/quiz-1.png%3Fraw%3Dtrue" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--BUFMF31I--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://github.com/skywind3000/KanaQuiz/blob/master/images/quiz-1.png%3Fraw%3Dtrue" alt="" width="286" height="357"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Read the kana character in the square brackets &lt;code&gt;[ ]&lt;/code&gt; and input its romanized name after the question mark ? then press Enter ASAP to continue.&lt;/p&gt;

&lt;p&gt;After finished, there will be a beautiful report:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--wWjHBWDg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://github.com/skywind3000/KanaQuiz/blob/master/images/report.png%3Fraw%3Dtrue" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--wWjHBWDg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://github.com/skywind3000/KanaQuiz/blob/master/images/report.png%3Fraw%3Dtrue" alt="" width="487" height="475"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Figure out which kana got the slowest response time (you are least likely to remember) and take time to practice.&lt;/p&gt;

&lt;p&gt;The history reports can always be queried by:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;python3 kanaquiz.py -q
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Enjoy.&lt;/p&gt;

</description>
      <category>linux</category>
      <category>japanese</category>
    </item>
    <item>
      <title>Vim 2022: Format your code in real-time !!</title>
      <dc:creator>Linwei</dc:creator>
      <pubDate>Mon, 13 Dec 2021 16:17:16 +0000</pubDate>
      <link>https://forem.com/skywind3000/vim-2022-format-your-code-in-real-time--5hch</link>
      <guid>https://forem.com/skywind3000/vim-2022-format-your-code-in-real-time--5hch</guid>
      <description>&lt;p&gt;There are plenty of code-formatting plugins, like &lt;a href="https://github.com/vim-autoformat/vim-autoformat"&gt;auto-format&lt;/a&gt; and &lt;a href="https://github.com/sbdchd/neoformat"&gt;neoformat&lt;/a&gt;, for vim. But all of them require running a certain command or using &lt;code&gt;:w&lt;/code&gt; to trigger formating.&lt;/p&gt;

&lt;p&gt;Is it possible to see the immediate formatted code in the real-time ? If so, life could be much easier.&lt;/p&gt;

&lt;p&gt;Therefore, I created a little plugin &lt;a href="https://github.com/skywind3000/vim-rt-format"&gt;vim-rt-format&lt;/a&gt;, which can format the current line immediately in INSERT mode as soon as you press ENTER:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--HrwfdbEm--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://github.com/skywind3000/images/raw/master/p/pep/rtformat_4.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--HrwfdbEm--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://github.com/skywind3000/images/raw/master/p/pep/rtformat_4.gif" alt="picture" width="718" height="474"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When you are focusing on editing, everything is done without paying extra attention. No need to stop your work to run an extra command like &lt;code&gt;gq&lt;/code&gt; or &lt;code&gt;:Neoformat&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Ready to try this out ? Firstly, &lt;code&gt;+python3&lt;/code&gt; feature must be enabled in your vim, check it by:&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="p"&gt;:&lt;/span&gt;echo &lt;span class="nb"&gt;has&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'python3'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It will return &lt;code&gt;1&lt;/code&gt; if python is supported in your current vim version. If not, install a new vim with &lt;code&gt;+python3&lt;/code&gt; feature, for example in ubuntu/debian:&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;sudo &lt;/span&gt;apt-get &lt;span class="nb"&gt;install &lt;/span&gt;vim-nox
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Secondly, a python module named &lt;code&gt;autopep8&lt;/code&gt; is required:&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;sudo &lt;/span&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;autopep8
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then add a few code in your &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 viml"&gt;&lt;code&gt;&lt;span class="c"&gt;" Install the plugin with vim-plug:&lt;/span&gt;
Plug &lt;span class="s1"&gt;'skywind3000/vim-rt-format'&lt;/span&gt;

&lt;span class="c"&gt;" By default, it will be triggered by `ENTER` in insert mode.&lt;/span&gt;
&lt;span class="c"&gt;" set this to 1 to use `CTRL+ENTER` instead, and keep the  &lt;/span&gt;
&lt;span class="c"&gt;" default `ENTER` behavior unchanged.&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;g:rtf_ctrl_enter&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;

&lt;span class="c"&gt;" Enable formatting when leaving insert mode&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;g:rtf_on_insert_leave&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And everything is ready, restart your vim, edit some files then you will have a nice day.&lt;/p&gt;

&lt;p&gt;BTW: Currently, it supports &lt;code&gt;python&lt;/code&gt;, &lt;code&gt;lua&lt;/code&gt; and &lt;code&gt;javascript&lt;/code&gt;.&lt;/p&gt;

</description>
      <category>vim</category>
      <category>productivity</category>
      <category>linux</category>
      <category>editor</category>
    </item>
    <item>
      <title>Vim 2021: Add A Context Menu in You Vim</title>
      <dc:creator>Linwei</dc:creator>
      <pubDate>Wed, 27 Jan 2021 07:58:12 +0000</pubDate>
      <link>https://forem.com/skywind3000/vim-2021-add-a-context-menu-in-you-vim-2pcc</link>
      <guid>https://forem.com/skywind3000/vim-2021-add-a-context-menu-in-you-vim-2pcc</guid>
      <description>&lt;p&gt;A nice looking context menu is very useful when you have something to do with current word/line under cursor. And it can also remind you when you forget your keymaps:&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%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fzd5op8x68wv9k8gh7n5b.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%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fzd5op8x68wv9k8gh7n5b.gif" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Setup
&lt;/h2&gt;

&lt;p&gt;With the help of the ui-extension plugin &lt;a href="https://github.com/skywind3000/vim-quickui" rel="noopener noreferrer"&gt;quickui&lt;/a&gt;, it can be simply defined like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight viml"&gt;&lt;code&gt;Plug &lt;span class="s1"&gt;'skywind3000/vim-quickui'&lt;/span&gt;

&lt;span class="c"&gt;" define your context menu as a list of (text, command) pairs&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;g:context_menu_k&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
&lt;span class="se"&gt;            \&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&amp;amp;Help Keyword\t\\ch"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'echo expand("&amp;lt;cword&amp;gt;")'&lt;/span&gt; &lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="se"&gt;            \&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&amp;amp;Signature\t\\cs"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'echo 101'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="se"&gt;            \&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'-'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="se"&gt;            \&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"Find in &amp;amp;File\t\\cx"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'exec "/" . expand("&amp;lt;cword&amp;gt;")'&lt;/span&gt; &lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="se"&gt;            \&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"Find in &amp;amp;Project\t\\cp"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'exec "vimgrep " . expand("&amp;lt;cword&amp;gt;") . "*"'&lt;/span&gt; &lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="se"&gt;            \&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"Find in &amp;amp;Defintion\t\\cd"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'YcmCompleter GotoDefinition'&lt;/span&gt; &lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="se"&gt;            \&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"Search &amp;amp;References\t\\cr"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'YcmCompleter GoToReferences'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="se"&gt;            \&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'-'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="se"&gt;            \&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&amp;amp;Documentation\t\\cm"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'exec "PyDoc " . expand("&amp;lt;cword&amp;gt;")'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="se"&gt;            \&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="c"&gt;" map 'K' to display the context menu&lt;/span&gt;
nnoremap &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;silent&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;K &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="k"&gt;call&lt;/span&gt; quickui#tools#clever_context&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'k'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;g:context_menu_k&lt;/span&gt;&lt;span class="p"&gt;,&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;p&gt;Then when you press &lt;code&gt;K&lt;/code&gt;, it will display around the cursor:&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%2Fskywind3000.github.io%2Fimages%2Fp%2Fquickui%2Fcontext.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%2Fskywind3000.github.io%2Fimages%2Fp%2Fquickui%2Fcontext.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Context menu is a good place to organize your LSP commands.&lt;/p&gt;

&lt;h2&gt;
  
  
  Usage
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;navigate the items by &lt;code&gt;j&lt;/code&gt;/&lt;code&gt;k&lt;/code&gt; or arrow keys.&lt;/li&gt;
&lt;li&gt;accept an item by &lt;code&gt;Enter&lt;/code&gt; or &lt;code&gt;Space&lt;/code&gt; or mouse left-click.&lt;/li&gt;
&lt;li&gt;press &lt;code&gt;ESC&lt;/code&gt; to quit.&lt;/li&gt;
&lt;li&gt;Hot keys can be defined by a &lt;code&gt;&amp;amp;&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The border and color are also customizable, check the quickui &lt;a href="https://github.com/skywind3000/vim-quickui" rel="noopener noreferrer"&gt;doc&lt;/a&gt; for more.&lt;/p&gt;

&lt;h2&gt;
  
  
  Plugin Dedicated Context
&lt;/h2&gt;

&lt;p&gt;Context menu can also be used to enhance plugin experience, you can setup some buffer local keymap in the plugin buffer:&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="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;g:context_menu_git&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
&lt;span class="se"&gt;      \&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&amp;amp;Stage (add)\ts"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'exec "normal s"'&lt;/span&gt; &lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="se"&gt;      \&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&amp;amp;Unstage (reset)\tu"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'exec "normal u"'&lt;/span&gt; &lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="se"&gt;      \&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&amp;amp;Toggle stage/unstage\t-"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'exec "normal -"'&lt;/span&gt; &lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="se"&gt;      \&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"Unstage &amp;amp;Everything\tU"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'exec "normal U"'&lt;/span&gt; &lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="se"&gt;      \&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"D&amp;amp;iscard change\tX"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'exec "normal X"'&lt;/span&gt; &lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="se"&gt;      \&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="se"&gt;      \&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"Inline &amp;amp;Diff\t="&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'exec "normal ="'&lt;/span&gt; &lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="se"&gt;      \&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"Diff S&amp;amp;plit\tdd"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'exec "normal dd"'&lt;/span&gt; &lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="se"&gt;      \&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"Diff &amp;amp;Horizontal\tdh"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'exec "normal dh"'&lt;/span&gt; &lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="se"&gt;      \&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"Diff &amp;amp;Vertical\tdv"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'exec "normal dv"'&lt;/span&gt; &lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="se"&gt;      \&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="se"&gt;      \&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&amp;amp;Open File\t&amp;lt;CR&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'exec "normal \&amp;lt;cr&amp;gt;"'&lt;/span&gt; &lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="se"&gt;      \&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"Open in New Split\to"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'exec "normal o"'&lt;/span&gt; &lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="se"&gt;      \&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"Open in New Vsplit\tgO"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'exec "normal gO"'&lt;/span&gt; &lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="se"&gt;      \&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"Open in New Tab\tO"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'exec "normal O"'&lt;/span&gt; &lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="se"&gt;      \&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"Open in &amp;amp;Preview\tp"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'exec "normal p"'&lt;/span&gt; &lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="se"&gt;      \&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="se"&gt;      \&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&amp;amp;Commit\tcc"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'exec "normal cc"'&lt;/span&gt; &lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="se"&gt;      \&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt; &lt;span class="nv"&gt;s:setup_fugitive&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    nnoremap &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;silent&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;K &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="k"&gt;call&lt;/span&gt; quickui#tools#clever_context&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'g'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;g:context_menu_git&lt;/span&gt;&lt;span class="p"&gt;,&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;
endfunc

augroup MenuEvents
    &lt;span class="k"&gt;au&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;
    &lt;span class="k"&gt;au&lt;/span&gt; &lt;span class="nb"&gt;FileType&lt;/span&gt; fugitive &lt;span class="k"&gt;call&lt;/span&gt; &lt;span class="nv"&gt;s:setup_fugitive&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
augroup END
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When you are using fugitive, you can press &lt;code&gt;K&lt;/code&gt; to display a fugitive menu:&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%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fe3lklalvoaafv31za09k.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%2Fi%2Fe3lklalvoaafv31za09k.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;No need to remember these seldom used fugitive keymaps, just &lt;code&gt;K&lt;/code&gt; is totally enough. &lt;/p&gt;

&lt;p&gt;You can also setup a context menu for &lt;a href="https://github.com/Shougo/defx.nvim" rel="noopener noreferrer"&gt;defx.nvim&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%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fqj8p0mba7fxzcrwlttav.jpg" 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%2Fi%2Fqj8p0mba7fxzcrwlttav.jpg" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This made defx more user-friendly.&lt;/p&gt;

</description>
      <category>vim</category>
      <category>productivity</category>
      <category>linux</category>
      <category>editor</category>
    </item>
    <item>
      <title>Bash cd bookmark in 20 lines</title>
      <dc:creator>Linwei</dc:creator>
      <pubDate>Mon, 20 Jan 2020 17:41:00 +0000</pubDate>
      <link>https://forem.com/skywind3000/bash-cd-bookmark-in-20-lines-40ip</link>
      <guid>https://forem.com/skywind3000/bash-cd-bookmark-in-20-lines-40ip</guid>
      <description>&lt;p&gt;This is a small bash script, save it as &lt;code&gt;m.sh&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;&lt;span class="c"&gt;# bash directory bookmark&lt;/span&gt;
&lt;span class="k"&gt;function &lt;/span&gt;cd_mark&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;MARKPATH&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;MARKPATH&lt;/span&gt;&lt;span class="k"&gt;:-&lt;/span&gt;&lt;span class="nv"&gt;$HOME&lt;/span&gt;&lt;span class="p"&gt;/.local/share/marks&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="nt"&gt;-d&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$MARKPATH&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="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; &lt;span class="nt"&gt;-m&lt;/span&gt; 700 &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$MARKPATH&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; 2&amp;gt; /dev/null
    &lt;span class="k"&gt;case&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="k"&gt;in&lt;/span&gt;
        +&lt;span class="k"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;            &lt;span class="c"&gt;# m +foo  - add new bookmark for $PWD&lt;/span&gt;
            &lt;span class="nb"&gt;ln&lt;/span&gt; &lt;span class="nt"&gt;-snf&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;pwd&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$MARKPATH&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;1&lt;/span&gt;:1&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="k"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;            &lt;span class="c"&gt;# m -foo  - delete a bookmark named "foo"&lt;/span&gt;
            &lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$MARKPATH&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;1&lt;/span&gt;:1&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="k"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;            &lt;span class="c"&gt;# m /bar  - search bookmarks matching "bar"&lt;/span&gt;
            find &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$MARKPATH&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-type&lt;/span&gt; l &lt;span class="nt"&gt;-name&lt;/span&gt; &lt;span class="s2"&gt;"*&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;1&lt;/span&gt;:1&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;*"&lt;/span&gt; | &lt;span class="se"&gt;\&lt;/span&gt;
                &lt;span class="nb"&gt;awk&lt;/span&gt; &lt;span class="nt"&gt;-F&lt;/span&gt; &lt;span class="s2"&gt;"/"&lt;/span&gt; &lt;span class="s1"&gt;'{print $NF}'&lt;/span&gt; | &lt;span class="nv"&gt;MARKPATH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$MARKPATH&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; xargs &lt;span class="nt"&gt;-I&lt;/span&gt;&lt;span class="s1"&gt;'{}'&lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
                sh &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s1"&gt;'echo "{} -&amp;gt;" $(readlink "$MARKPATH/{}")'&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="c"&gt;# m       - list all bookmarks&lt;/span&gt;
            &lt;span class="nb"&gt;command ls&lt;/span&gt; &lt;span class="nt"&gt;-1&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$MARKPATH&lt;/span&gt;&lt;span class="s2"&gt;/"&lt;/span&gt; | &lt;span class="nv"&gt;MARKPATH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$MARKPATH&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; xargs &lt;span class="nt"&gt;-I&lt;/span&gt;&lt;span class="s1"&gt;'{}'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
                sh &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s1"&gt;'echo "{} -&amp;gt;" $(readlink "$MARKPATH/{}")'&lt;/span&gt;
            &lt;span class="p"&gt;;;&lt;/span&gt;
        &lt;span class="k"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;             &lt;span class="c"&gt;# m foo   - cd to the bookmark directory&lt;/span&gt;
            &lt;span class="nb"&gt;local &lt;/span&gt;&lt;span class="nv"&gt;dest&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;&lt;span class="nb"&gt;readlink&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$MARKPATH&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; 2&amp;gt; /dev/null&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="nt"&gt;-d&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$dest&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="nb"&gt;cd&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$dest&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"No such mark: &lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
            &lt;span class="p"&gt;;;&lt;/span&gt;
    &lt;span class="k"&gt;esac&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;# by default, alias cd_mark to m&lt;/span&gt;
&lt;span class="nb"&gt;alias&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;MARKCMD&lt;/span&gt;&lt;span class="k"&gt;:-&lt;/span&gt;&lt;span class="nv"&gt;m&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'cd_mark'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then put a single line in your &lt;code&gt;.bashrc&lt;/code&gt; or &lt;code&gt;.zshrc&lt;/code&gt;:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;source /path/to/m.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Or, you can simply copy &amp;amp; paste the content to your &lt;code&gt;.bashrc&lt;/code&gt; or &lt;code&gt;.zshrc&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Now you can have your &lt;code&gt;m&lt;/code&gt; command to manipulate the directory bookmarks:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;m +foo&lt;/code&gt;: add a new bookmark for your current working directory&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;m -foo&lt;/code&gt;: delete a bookmark&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;m foo&lt;/code&gt;: cd to the given bookmark directory&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;m /bar&lt;/code&gt;: search bookmarks matching "bar"&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;m&lt;/code&gt;: print a list of all bookmarks&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;cd&lt;/code&gt; to your most recently accessed directories and use &lt;code&gt;m +foo&lt;/code&gt; to create a bookmark named &lt;code&gt;foo&lt;/code&gt;, and use &lt;code&gt;m foo&lt;/code&gt; to go back at anytime.&lt;/p&gt;

&lt;p&gt;Let's polish it a little, for example, add a completion function for bash/zsh:&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="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="nv"&gt;$BASH_VERSION&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
    function &lt;/span&gt;_cdmark_complete&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nb"&gt;local &lt;/span&gt;&lt;span class="nv"&gt;MARKPATH&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;MARKPATH&lt;/span&gt;&lt;span class="k"&gt;:-&lt;/span&gt;&lt;span class="nv"&gt;$HOME&lt;/span&gt;&lt;span class="p"&gt;/.local/share/marks&lt;/span&gt;&lt;span class="k"&gt;}&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;curword&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;COMP_WORDS&lt;/span&gt;&lt;span class="p"&gt;[COMP_CWORD]&lt;/span&gt;&lt;span class="k"&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="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$curword&lt;/span&gt;&lt;span class="s2"&gt;"&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="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="nv"&gt;COMPREPLY&lt;/span&gt;&lt;span class="o"&gt;=(&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;find &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$MARKPATH&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-type&lt;/span&gt; l &lt;span class="nt"&gt;-name&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;curword&lt;/span&gt;:1&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;*"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
                2&amp;gt; /dev/null | &lt;span class="nb"&gt;awk&lt;/span&gt; &lt;span class="nt"&gt;-F&lt;/span&gt; &lt;span class="s2"&gt;"/"&lt;/span&gt; &lt;span class="s1"&gt;'{print "-"$NF}'&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;else
            &lt;/span&gt;&lt;span class="nv"&gt;COMPREPLY&lt;/span&gt;&lt;span class="o"&gt;=(&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;find &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$MARKPATH&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-type&lt;/span&gt; l &lt;span class="nt"&gt;-name&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;curword&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;*"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
                2&amp;gt; /dev/null | &lt;span class="nb"&gt;awk&lt;/span&gt; &lt;span class="nt"&gt;-F&lt;/span&gt; &lt;span class="s2"&gt;"/"&lt;/span&gt; &lt;span class="s1"&gt;'{print $NF}'&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;fi&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="nb"&gt;complete&lt;/span&gt; &lt;span class="nt"&gt;-F&lt;/span&gt; _cdmark_complete &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;MARKCMD&lt;/span&gt;&lt;span class="k"&gt;:-&lt;/span&gt;&lt;span class="nv"&gt;m&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;elif&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="nv"&gt;$ZSH_VERSION&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
    function &lt;/span&gt;_cdmark_complete&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nb"&gt;local &lt;/span&gt;&lt;span class="nv"&gt;MARKPATH&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;MARKPATH&lt;/span&gt;&lt;span class="k"&gt;:-&lt;/span&gt;&lt;span class="nv"&gt;$HOME&lt;/span&gt;&lt;span class="p"&gt;/.local/share/marks&lt;/span&gt;&lt;span class="k"&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="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;1&lt;/span&gt;&lt;span class="k"&gt;}${&lt;/span&gt;&lt;span class="nv"&gt;2&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="s2"&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
            &lt;/span&gt;&lt;span class="nv"&gt;reply&lt;/span&gt;&lt;span class="o"&gt;=(&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;command ls&lt;/span&gt; &lt;span class="nt"&gt;-1&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$MARKPATH&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; 2&amp;gt; /dev/null | &lt;span class="se"&gt;\&lt;/span&gt;
                &lt;span class="nb"&gt;awk&lt;/span&gt; &lt;span class="s1"&gt;'{print "-"$0}'&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;else
            &lt;/span&gt;&lt;span class="nv"&gt;reply&lt;/span&gt;&lt;span class="o"&gt;=(&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;command ls&lt;/span&gt; &lt;span class="nt"&gt;-1&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$MARKPATH&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; 2&amp;gt; /dev/null&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;fi&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
    compctl &lt;span class="nt"&gt;-K&lt;/span&gt; _cdmark_complete cd_mark
&lt;span class="k"&gt;fi&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;After that, when you press tab after &lt;code&gt;m&lt;/code&gt; command, you can get suggestions from the completion function.&lt;/p&gt;

</description>
      <category>bash</category>
      <category>linux</category>
      <category>productivity</category>
      <category>beginners</category>
    </item>
  </channel>
</rss>
