Add using clap
This commit is contained in:
parent
a019e5eba9
commit
41d0455864
10 changed files with 387 additions and 10 deletions
BIN
assets/using-clap/1.png
Normal file
BIN
assets/using-clap/1.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 38 KiB |
|
@ -20,7 +20,7 @@
|
||||||
<p>The datasets being used for this test will be the
|
<p>The datasets being used for this test will be the
|
||||||
following:</p>
|
following:</p>
|
||||||
<ul>
|
<ul>
|
||||||
<li>25 GB of null data (just <code>000000000000</code> in
|
<li>25 GB of null data (just <code>00000000</code> in
|
||||||
binary)</li>
|
binary)</li>
|
||||||
<li>25 GB of random data<a href="#fn1" class="footnote-ref"
|
<li>25 GB of random data<a href="#fn1" class="footnote-ref"
|
||||||
id="fnref1" role="doc-noteref"><sup>1</sup></a></li>
|
id="fnref1" role="doc-noteref"><sup>1</sup></a></li>
|
||||||
|
@ -33,7 +33,7 @@
|
||||||
<li>For some rough latency testing:
|
<li>For some rough latency testing:
|
||||||
<ul>
|
<ul>
|
||||||
<li>1000 4 kilobyte files filled with null data (again, just
|
<li>1000 4 kilobyte files filled with null data (again, just
|
||||||
<code>0000000</code> in binary)</li>
|
<code>00000000</code> in binary)</li>
|
||||||
<li>1000 4 kilobyte files filled with random data</li>
|
<li>1000 4 kilobyte files filled with random data</li>
|
||||||
</ul></li>
|
</ul></li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
|
@ -6,12 +6,12 @@ DwarFS is a filesystem developed by the user mhx on GitHub [1], which is self-de
|
||||||
|
|
||||||
The datasets being used for this test will be the following:
|
The datasets being used for this test will be the following:
|
||||||
|
|
||||||
- 25 GB of null data (just `000000000000` in binary)
|
- 25 GB of null data (just `00000000` in binary)
|
||||||
- 25 GB of random data[^1]
|
- 25 GB of random data[^1]
|
||||||
- Data for a 100 million-sided regular polygon; ~29 GB[^2]
|
- Data for a 100 million-sided regular polygon; ~29 GB[^2]
|
||||||
- The current Linux longterm release source ([6.6.58](https://cdn.kernel.org/pub/linux/kernel/v6.x/linux-6.6.58.tar.xz) [2]); ~1.5 GB
|
- The current Linux longterm release source ([6.6.58](https://cdn.kernel.org/pub/linux/kernel/v6.x/linux-6.6.58.tar.xz) [2]); ~1.5 GB
|
||||||
- For some rough latency testing:
|
- For some rough latency testing:
|
||||||
- 1000 4 kilobyte files filled with null data (again, just `0000000` in binary)
|
- 1000 4 kilobyte files filled with null data (again, just `00000000` in binary)
|
||||||
- 1000 4 kilobyte files filled with random data
|
- 1000 4 kilobyte files filled with random data
|
||||||
|
|
||||||
All this data should cover both latency and read speed testing for data that compresses differently - extremely compressible files with null data, decently compressible files, and random data which can't be compressed well.
|
All this data should cover both latency and read speed testing for data that compresses differently - extremely compressible files with null data, decently compressible files, and random data which can't be compressed well.
|
||||||
|
|
195
blog/using-clap.html
Normal file
195
blog/using-clap.html
Normal file
|
@ -0,0 +1,195 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta content="width=device-width, initial-scale=1" charset="utf-8" />
|
||||||
|
<title>Using `clap`</title>
|
||||||
|
<link href="/style.css" type="text/css" rel="stylesheet" />
|
||||||
|
<link href="/prism.css" type="text/css" rel="stylesheet" />
|
||||||
|
</head>
|
||||||
|
<body class="line-numbers">
|
||||||
|
<h1 id="using-clap">Using <code>clap</code></h1>
|
||||||
|
<p>Clap stands for Command Line Argument Parser, and put simply,
|
||||||
|
it's a great library for making command-line stuff with Rust.
|
||||||
|
Even Cargo, Rust's package manager, depends on it [4], and it's
|
||||||
|
been downloaded over 300 million times [5].</p>
|
||||||
|
<p>Rather than going over everything clap can do, I'll go over
|
||||||
|
how I've used it in my <code>disk-read-benchmark</code> program
|
||||||
|
I'll be using in my next blog post.</p>
|
||||||
|
<h2 id="basics">Basics</h2>
|
||||||
|
<p>First off, we need to install <code>clap</code>; make sure to
|
||||||
|
enable its <code>derive</code> feature as that's what we'll be
|
||||||
|
using.</p>
|
||||||
|
<div class="sourceCode" id="cb1"><pre
|
||||||
|
class="language-sh"><code class="language-bash"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="ex">cargo</span> add clap <span class="at">--features</span> derive</span></code></pre></div>
|
||||||
|
<p>First off, we need to get a bit of code just to start
|
||||||
|
off:</p>
|
||||||
|
<div class="sourceCode" id="cb2"><pre
|
||||||
|
class="language-rust"><code class="language-rust"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="kw">use</span> <span class="pp">clap::</span><span class="op">{</span>Parser<span class="op">,</span> Subcommand<span class="op">};</span></span>
|
||||||
|
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a></span>
|
||||||
|
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a><span class="at">#[</span>derive<span class="at">(</span>Parser<span class="at">)]</span></span>
|
||||||
|
<span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a><span class="at">#[</span>command<span class="at">(</span>version<span class="op">,</span> about<span class="op">,</span> long_about <span class="op">=</span> <span class="cn">None</span><span class="at">)]</span></span>
|
||||||
|
<span id="cb2-5"><a href="#cb2-5" aria-hidden="true" tabindex="-1"></a><span class="kw">pub</span> <span class="kw">struct</span> Cli <span class="op">{</span></span>
|
||||||
|
<span id="cb2-6"><a href="#cb2-6" aria-hidden="true" tabindex="-1"></a> <span class="at">#[</span>command<span class="at">(</span>subcommand<span class="at">)]</span></span>
|
||||||
|
<span id="cb2-7"><a href="#cb2-7" aria-hidden="true" tabindex="-1"></a> <span class="kw">pub</span> command<span class="op">:</span> Commands<span class="op">,</span></span>
|
||||||
|
<span id="cb2-8"><a href="#cb2-8" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
|
||||||
|
<p>This has the built-in "version" and "about" options, with the
|
||||||
|
long "about" option disabled.</p>
|
||||||
|
<p>Next, we need to list all out commands we'll have:</p>
|
||||||
|
<div class="sourceCode" id="cb3"><pre
|
||||||
|
class="language-rust"><code class="language-rust"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="at">#[</span>derive<span class="at">(</span>Subcommand<span class="at">)]</span></span>
|
||||||
|
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a><span class="kw">pub</span> <span class="kw">enum</span> Commands <span class="op">{</span></span>
|
||||||
|
<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a> <span class="co">///Run this thing</span></span>
|
||||||
|
<span id="cb3-4"><a href="#cb3-4" aria-hidden="true" tabindex="-1"></a> Run<span class="op">,</span></span>
|
||||||
|
<span id="cb3-5"><a href="#cb3-5" aria-hidden="true" tabindex="-1"></a> <span class="co">///Delete the stuff that thing does</span></span>
|
||||||
|
<span id="cb3-6"><a href="#cb3-6" aria-hidden="true" tabindex="-1"></a> Delete<span class="op">,</span></span>
|
||||||
|
<span id="cb3-7"><a href="#cb3-7" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
|
||||||
|
<p>The documentation comments (<code>///</code>) should
|
||||||
|
<em>not</em> have a space after the slashes, as otherwise the
|
||||||
|
program will have an extra space where it shouldn't.</p>
|
||||||
|
<p>Finally, we create the <code>main()</code> function. First it
|
||||||
|
parses everything, then checks what command was run and runs the
|
||||||
|
relevant code.</p>
|
||||||
|
<div class="sourceCode" id="cb4"><pre
|
||||||
|
class="language-rust"><code class="language-rust"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a><span class="kw">fn</span> main() <span class="op">{</span></span>
|
||||||
|
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a> <span class="kw">let</span> cli <span class="op">=</span> <span class="pp">Cli::</span>parse()<span class="op">;</span></span>
|
||||||
|
<span id="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a></span>
|
||||||
|
<span id="cb4-4"><a href="#cb4-4" aria-hidden="true" tabindex="-1"></a> <span class="cf">match</span> cli<span class="op">.</span>command <span class="op">{</span></span>
|
||||||
|
<span id="cb4-5"><a href="#cb4-5" aria-hidden="true" tabindex="-1"></a> <span class="pp">Commands::</span>Run <span class="op">{</span></span>
|
||||||
|
<span id="cb4-6"><a href="#cb4-6" aria-hidden="true" tabindex="-1"></a> run()<span class="op">;</span></span>
|
||||||
|
<span id="cb4-7"><a href="#cb4-7" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
|
||||||
|
<span id="cb4-8"><a href="#cb4-8" aria-hidden="true" tabindex="-1"></a> <span class="pp">Commands::</span>Delete <span class="op">{</span></span>
|
||||||
|
<span id="cb4-9"><a href="#cb4-9" aria-hidden="true" tabindex="-1"></a> delete()<span class="op">;</span></span>
|
||||||
|
<span id="cb4-10"><a href="#cb4-10" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
|
||||||
|
<span id="cb4-11"><a href="#cb4-11" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
|
||||||
|
<span id="cb4-12"><a href="#cb4-12" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
|
||||||
|
<p>That's all you need to know to use <code>clap</code> at a
|
||||||
|
very basic level; for more details, check out the docs [1]. But,
|
||||||
|
you probably don't want to have to type in the entire command
|
||||||
|
automatically, autocomplete would be nice. So I'll also go over
|
||||||
|
how to use <code>clap_complete</code> as well.</p>
|
||||||
|
<h2 id="clap_complete"><code>clap_complete</code></h2>
|
||||||
|
<p>Searching through the documentation [2], you'll notice that
|
||||||
|
the docs don't cover how to use it with clap's derive at all.
|
||||||
|
Instead, after some Googling, I found an example script in
|
||||||
|
<em>clap</em>'s repository [3], which I then adapted and played
|
||||||
|
around with a bit until I got it figured out.</p>
|
||||||
|
<p>Anyways, again, we need to install <code>clap_complete</code>
|
||||||
|
first:</p>
|
||||||
|
<div class="sourceCode" id="cb5"><pre
|
||||||
|
class="language-sh"><code class="language-bash"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a><span class="ex">cargo</span> add clap_complete</span></code></pre></div>
|
||||||
|
<p>Then, add the relevant imports. We'll just being doing it for
|
||||||
|
the fish shell since that's what I use, so we'll only import
|
||||||
|
<code>Fish</code>; Bash, Zsh, PowerShell, and Elvish are also
|
||||||
|
supported.</p>
|
||||||
|
<div class="sourceCode" id="cb6"><pre
|
||||||
|
class="language-rust"><code class="language-rust"><span id="cb6-1"><a href="#cb6-1" aria-hidden="true" tabindex="-1"></a><span class="kw">use</span> <span class="pp">clap_complete::aot::</span><span class="op">{</span>generate<span class="op">,</span> Fish<span class="op">};</span></span></code></pre></div>
|
||||||
|
<p>Then, we need to add a command to generate the
|
||||||
|
completion:</p>
|
||||||
|
<div class="sourceCode" id="cb7"><pre
|
||||||
|
class="language-rust"><code class="language-rust"><span id="cb7-1"><a href="#cb7-1" aria-hidden="true" tabindex="-1"></a><span class="at">#[</span>derive<span class="at">(</span>Subcommand<span class="at">)]</span></span>
|
||||||
|
<span id="cb7-2"><a href="#cb7-2" aria-hidden="true" tabindex="-1"></a><span class="kw">pub</span> <span class="kw">enum</span> Commands <span class="op">{</span></span>
|
||||||
|
<span id="cb7-3"><a href="#cb7-3" aria-hidden="true" tabindex="-1"></a> <span class="co">///Run this thing</span></span>
|
||||||
|
<span id="cb7-4"><a href="#cb7-4" aria-hidden="true" tabindex="-1"></a> Run<span class="op">,</span></span>
|
||||||
|
<span id="cb7-5"><a href="#cb7-5" aria-hidden="true" tabindex="-1"></a> <span class="co">///Delete the stuff that thing does</span></span>
|
||||||
|
<span id="cb7-6"><a href="#cb7-6" aria-hidden="true" tabindex="-1"></a> Delete<span class="op">,</span></span>
|
||||||
|
<span id="cb7-7"><a href="#cb7-7" aria-hidden="true" tabindex="-1"></a> <span class="co">///Generate fish completions</span></span>
|
||||||
|
<span id="cb7-8"><a href="#cb7-8" aria-hidden="true" tabindex="-1"></a> FishCompletions<span class="op">,</span></span>
|
||||||
|
<span id="cb7-9"><a href="#cb7-9" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
|
||||||
|
<p>Next, we actually generate the completion, adding it like
|
||||||
|
it's another command:</p>
|
||||||
|
<div class="sourceCode" id="cb8"><pre
|
||||||
|
class="language-rust"><code class="language-rust"><span id="cb8-1"><a href="#cb8-1" aria-hidden="true" tabindex="-1"></a> <span class="cf">match</span> cli<span class="op">.</span>command <span class="op">{</span></span>
|
||||||
|
<span id="cb8-2"><a href="#cb8-2" aria-hidden="true" tabindex="-1"></a> <span class="pp">Commands::</span>Run <span class="op">{</span></span>
|
||||||
|
<span id="cb8-3"><a href="#cb8-3" aria-hidden="true" tabindex="-1"></a> run()<span class="op">;</span></span>
|
||||||
|
<span id="cb8-4"><a href="#cb8-4" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
|
||||||
|
<span id="cb8-5"><a href="#cb8-5" aria-hidden="true" tabindex="-1"></a> <span class="pp">Commands::</span>Delete <span class="op">{</span></span>
|
||||||
|
<span id="cb8-6"><a href="#cb8-6" aria-hidden="true" tabindex="-1"></a> delete()<span class="op">;</span></span>
|
||||||
|
<span id="cb8-7"><a href="#cb8-7" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
|
||||||
|
<span id="cb8-8"><a href="#cb8-8" aria-hidden="true" tabindex="-1"></a> <span class="pp">Commands::</span>GenerateFishCompletions <span class="op">=></span> <span class="op">{</span></span>
|
||||||
|
<span id="cb8-9"><a href="#cb8-9" aria-hidden="true" tabindex="-1"></a> generate(</span>
|
||||||
|
<span id="cb8-10"><a href="#cb8-10" aria-hidden="true" tabindex="-1"></a> Fish<span class="op">,</span></span>
|
||||||
|
<span id="cb8-11"><a href="#cb8-11" aria-hidden="true" tabindex="-1"></a> <span class="op">&</span><span class="kw">mut</span> <span class="pp">Cli::</span>command()<span class="op">,</span></span>
|
||||||
|
<span id="cb8-12"><a href="#cb8-12" aria-hidden="true" tabindex="-1"></a> <span class="st">"example-program"</span><span class="op">,</span></span>
|
||||||
|
<span id="cb8-13"><a href="#cb8-13" aria-hidden="true" tabindex="-1"></a> <span class="op">&</span><span class="kw">mut</span> stdout()<span class="op">,</span></span>
|
||||||
|
<span id="cb8-14"><a href="#cb8-14" aria-hidden="true" tabindex="-1"></a> )<span class="op">;</span></span>
|
||||||
|
<span id="cb8-15"><a href="#cb8-15" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
|
||||||
|
<span id="cb8-16"><a href="#cb8-16" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span></code></pre></div>
|
||||||
|
<p>To explain the options for <code>generate()</code>:</p>
|
||||||
|
<ul>
|
||||||
|
<li><code>Fish</code>: The shell we're using.</li>
|
||||||
|
<li><code>&mut Cli::command()</code>: I don't actually know
|
||||||
|
what this does, but understanding ths library fully this is
|
||||||
|
beyond my pay grade, especially given the somewhat lacking
|
||||||
|
docs.</li>
|
||||||
|
<li><code>"example-program"</code>: The name of our program</li>
|
||||||
|
<li><code>&mut stdout()</code>: <code>stdout</code>, so that
|
||||||
|
it can print the completions. Why does it do it this way? I
|
||||||
|
don't know, it doesn't make sense to me. Why doesn't it just
|
||||||
|
return it as a String? I don't know. But it works, I
|
||||||
|
suppose.</li>
|
||||||
|
</ul>
|
||||||
|
<p>As an example of all this, here's my
|
||||||
|
<code>disk-read-benchmark</code> program, running using all
|
||||||
|
this. The commands have formatting I can't do, so it looks even
|
||||||
|
better than I can even show here.</p>
|
||||||
|
<div class="sourceCode" id="cb9"><pre
|
||||||
|
class="language-txt"><code class="language-default"><span id="cb9-1"><a href="#cb9-1" aria-hidden="true" tabindex="-1"></a>~> disk-read-benchmark</span>
|
||||||
|
<span id="cb9-2"><a href="#cb9-2" aria-hidden="true" tabindex="-1"></a>Usage: disk-read-benchmark <COMMAND></span>
|
||||||
|
<span id="cb9-3"><a href="#cb9-3" aria-hidden="true" tabindex="-1"></a></span>
|
||||||
|
<span id="cb9-4"><a href="#cb9-4" aria-hidden="true" tabindex="-1"></a>Commands:</span>
|
||||||
|
<span id="cb9-5"><a href="#cb9-5" aria-hidden="true" tabindex="-1"></a> generate-bash-completions Generate bash completions</span>
|
||||||
|
<span id="cb9-6"><a href="#cb9-6" aria-hidden="true" tabindex="-1"></a> generate-zsh-completions Generate zsh completions</span>
|
||||||
|
<span id="cb9-7"><a href="#cb9-7" aria-hidden="true" tabindex="-1"></a> generate-fish-completions Generate fish completions</span>
|
||||||
|
<span id="cb9-8"><a href="#cb9-8" aria-hidden="true" tabindex="-1"></a> grab-data Grabs the datasets used for benchmarking</span>
|
||||||
|
<span id="cb9-9"><a href="#cb9-9" aria-hidden="true" tabindex="-1"></a> benchmark Runs the benchmark</span>
|
||||||
|
<span id="cb9-10"><a href="#cb9-10" aria-hidden="true" tabindex="-1"></a> prep-dirs Prepares the directories so other programs can prepare their datasets</span>
|
||||||
|
<span id="cb9-11"><a href="#cb9-11" aria-hidden="true" tabindex="-1"></a> run Runs it all</span>
|
||||||
|
<span id="cb9-12"><a href="#cb9-12" aria-hidden="true" tabindex="-1"></a> help Print this message or the help of the given subcommand(s)</span>
|
||||||
|
<span id="cb9-13"><a href="#cb9-13" aria-hidden="true" tabindex="-1"></a></span>
|
||||||
|
<span id="cb9-14"><a href="#cb9-14" aria-hidden="true" tabindex="-1"></a>Options:</span>
|
||||||
|
<span id="cb9-15"><a href="#cb9-15" aria-hidden="true" tabindex="-1"></a> -h, --help Print help</span>
|
||||||
|
<span id="cb9-16"><a href="#cb9-16" aria-hidden="true" tabindex="-1"></a> -V, --version Print version</span>
|
||||||
|
<span id="cb9-17"><a href="#cb9-17" aria-hidden="true" tabindex="-1"></a>~> disk-read-benchmark generate-fish-completions | source</span>
|
||||||
|
<span id="cb9-18"><a href="#cb9-18" aria-hidden="true" tabindex="-1"></a>~> disk-read-benchmark benchmark --help</span>
|
||||||
|
<span id="cb9-19"><a href="#cb9-19" aria-hidden="true" tabindex="-1"></a>Runs the benchmark</span>
|
||||||
|
<span id="cb9-20"><a href="#cb9-20" aria-hidden="true" tabindex="-1"></a></span>
|
||||||
|
<span id="cb9-21"><a href="#cb9-21" aria-hidden="true" tabindex="-1"></a>Usage: disk-read-benchmark benchmark</span>
|
||||||
|
<span id="cb9-22"><a href="#cb9-22" aria-hidden="true" tabindex="-1"></a></span>
|
||||||
|
<span id="cb9-23"><a href="#cb9-23" aria-hidden="true" tabindex="-1"></a>Options:</span>
|
||||||
|
<span id="cb9-24"><a href="#cb9-24" aria-hidden="true" tabindex="-1"></a> -h, --help Print help</span></code></pre></div>
|
||||||
|
<p>To better see how great it looks, here's a screenshot:</p>
|
||||||
|
<img src="/assets/using-clap/1.png"
|
||||||
|
title="The same output, but with very nice formatting - underlining and bolding for headers and the tables" alt="The same output, but with very nice formatting - underlining and bolding for headers and the tables" />
|
||||||
|
<p>Pressing tab twice after entering
|
||||||
|
<code>disk-read-benchmark</code> displays the completions, which
|
||||||
|
I can select and use like any other program's.</p>
|
||||||
|
<div class="sourceCode" id="cb10"><pre
|
||||||
|
class="language-txt"><code class="language-default"><span id="cb10-1"><a href="#cb10-1" aria-hidden="true" tabindex="-1"></a>~> disk-read-benchmark</span>
|
||||||
|
<span id="cb10-2"><a href="#cb10-2" aria-hidden="true" tabindex="-1"></a>benchmark (Runs the benchmark) grab-data (Grabs the datasets used for benchmarking)</span>
|
||||||
|
<span id="cb10-3"><a href="#cb10-3" aria-hidden="true" tabindex="-1"></a>generate-bash-completions (Generate bash completions) help (Print this message or the help of the given subcommand(s))</span>
|
||||||
|
<span id="cb10-4"><a href="#cb10-4" aria-hidden="true" tabindex="-1"></a>generate-fish-completions (Generate fish completions) prep-dirs (Prepares the directories so other programs can prepare their datasets)</span>
|
||||||
|
<span id="cb10-5"><a href="#cb10-5" aria-hidden="true" tabindex="-1"></a>generate-zsh-completions (Generate zsh completions) run (Runs it all)</span></code></pre></div>
|
||||||
|
<h2 id="sources">Sources</h2>
|
||||||
|
<ol type="1">
|
||||||
|
<li><a href="https://docs.rs/clap/latest/clap/"
|
||||||
|
class="uri">https://docs.rs/clap/latest/clap/</a></li>
|
||||||
|
<li><a
|
||||||
|
href="https://docs.rs/clap_complete/latest/clap_complete/"
|
||||||
|
class="uri">https://docs.rs/clap_complete/latest/clap_complete/</a></li>
|
||||||
|
<li><a
|
||||||
|
href="https://github.com/clap-rs/clap/blob/master/clap_complete/examples/completion-derive.rs"
|
||||||
|
class="uri">https://github.com/clap-rs/clap/blob/master/clap_complete/examples/completion-derive.rs</a></li>
|
||||||
|
<li><a
|
||||||
|
href="https://github.com/rust-lang/cargo/blob/master/Cargo.toml"
|
||||||
|
class="uri">https://github.com/rust-lang/cargo/blob/master/Cargo.toml</a></li>
|
||||||
|
<li><a href="https://crates.io/crates/clap"
|
||||||
|
class="uri">https://crates.io/crates/clap</a></li>
|
||||||
|
</ol>
|
||||||
|
<iframe src="https://john.citrons.xyz/embed?ref=askiiart.net" style="margin-left:auto;display:block;margin-right:auto;max-width:732px;width:100%;height:94px;border:none;"></iframe>
|
||||||
|
<script src="/prism.js"></script>
|
||||||
|
</body>
|
||||||
|
<footer>
|
||||||
|
<p><a href="https://git.askiiart.net/askiiart/engl-2311-blog">Source code</a> | <a href="/feed.xml">RSS</a> | <a href="/glossary.html">Glossary</a> | <a href="/about.html">About</a></p>
|
||||||
|
<small>Image captions are the same as the alt text; assuming you're sighted, you can most likely ignore them.</small>
|
||||||
|
</footer>
|
||||||
|
</html>
|
170
blog/using-clap.md
Normal file
170
blog/using-clap.md
Normal file
|
@ -0,0 +1,170 @@
|
||||||
|
# Using `clap`
|
||||||
|
|
||||||
|
Clap stands for Command Line Argument Parser, and put simply, it's a great library for making command-line stuff with Rust. Even Cargo, Rust's package manager, depends on it [4], and it's been downloaded over 300 million times [5].
|
||||||
|
|
||||||
|
Rather than going over everything clap can do, I'll go over how I've used it in my `disk-read-benchmark` program I'll be using in my next blog post.
|
||||||
|
|
||||||
|
## Basics
|
||||||
|
|
||||||
|
First off, we need to install `clap`; make sure to enable its `derive` feature as that's what we'll be using.
|
||||||
|
|
||||||
|
```sh
|
||||||
|
cargo add clap --features derive
|
||||||
|
```
|
||||||
|
|
||||||
|
First off, we need to get a bit of code just to start off:
|
||||||
|
|
||||||
|
```rust
|
||||||
|
use clap::{Parser, Subcommand};
|
||||||
|
|
||||||
|
#[derive(Parser)]
|
||||||
|
#[command(version, about, long_about = None)]
|
||||||
|
pub struct Cli {
|
||||||
|
#[command(subcommand)]
|
||||||
|
pub command: Commands,
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
This has the built-in "version" and "about" options, with the long "about" option disabled.
|
||||||
|
|
||||||
|
Next, we need to list all out commands we'll have:
|
||||||
|
|
||||||
|
```rust
|
||||||
|
#[derive(Subcommand)]
|
||||||
|
pub enum Commands {
|
||||||
|
///Run this thing
|
||||||
|
Run,
|
||||||
|
///Delete the stuff that thing does
|
||||||
|
Delete,
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
The documentation comments (`///`) should *not* have a space after the slashes, as otherwise the program will have an extra space where it shouldn't.
|
||||||
|
|
||||||
|
Finally, we create the `main()` function. First it parses everything, then checks what command was run and runs the relevant code.
|
||||||
|
|
||||||
|
```rust
|
||||||
|
fn main() {
|
||||||
|
let cli = Cli::parse();
|
||||||
|
|
||||||
|
match cli.command {
|
||||||
|
Commands::Run {
|
||||||
|
run();
|
||||||
|
}
|
||||||
|
Commands::Delete {
|
||||||
|
delete();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
That's all you need to know to use `clap` at a very basic level; for more details, check out the docs [1]. But, you probably don't want to have to type in the entire command automatically, autocomplete would be nice. So I'll also go over how to use `clap_complete` as well.
|
||||||
|
|
||||||
|
## `clap_complete`
|
||||||
|
|
||||||
|
Searching through the documentation [2], you'll notice that the docs don't cover how to use it with clap's derive at all. Instead, after some Googling, I found an example script in *clap*'s repository [3], which I then adapted and played around with a bit until I got it figured out.
|
||||||
|
|
||||||
|
Anyways, again, we need to install `clap_complete` first:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
cargo add clap_complete
|
||||||
|
```
|
||||||
|
|
||||||
|
Then, add the relevant imports. We'll just being doing it for the fish shell since that's what I use, so we'll only import `Fish`; Bash, Zsh, PowerShell, and Elvish are also supported.
|
||||||
|
|
||||||
|
```rust
|
||||||
|
use clap_complete::aot::{generate, Fish};
|
||||||
|
```
|
||||||
|
|
||||||
|
Then, we need to add a command to generate the completion:
|
||||||
|
|
||||||
|
```rust
|
||||||
|
#[derive(Subcommand)]
|
||||||
|
pub enum Commands {
|
||||||
|
///Run this thing
|
||||||
|
Run,
|
||||||
|
///Delete the stuff that thing does
|
||||||
|
Delete,
|
||||||
|
///Generate fish completions
|
||||||
|
FishCompletions,
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Next, we actually generate the completion, adding it like it's another command:
|
||||||
|
|
||||||
|
```rust
|
||||||
|
match cli.command {
|
||||||
|
Commands::Run {
|
||||||
|
run();
|
||||||
|
}
|
||||||
|
Commands::Delete {
|
||||||
|
delete();
|
||||||
|
}
|
||||||
|
Commands::GenerateFishCompletions => {
|
||||||
|
generate(
|
||||||
|
Fish,
|
||||||
|
&mut Cli::command(),
|
||||||
|
"example-program",
|
||||||
|
&mut stdout(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
To explain the options for `generate()`:
|
||||||
|
|
||||||
|
- `Fish`: The shell we're using.
|
||||||
|
- `&mut Cli::command()`: I don't actually know what this does, but understanding ths library fully this is beyond my pay grade, especially given the somewhat lacking docs.
|
||||||
|
- `"example-program"`: The name of our program
|
||||||
|
- `&mut stdout()`: `stdout`, so that it can print the completions. Why does it do it this way? I don't know, it doesn't make sense to me. Why doesn't it just return it as a String? I don't know. But it works, I suppose.
|
||||||
|
|
||||||
|
As an example of all this, here's my `disk-read-benchmark` program, running using all this. The commands have formatting I can't do, so it looks even better than I can even show here.
|
||||||
|
|
||||||
|
```txt
|
||||||
|
~> disk-read-benchmark
|
||||||
|
Usage: disk-read-benchmark <COMMAND>
|
||||||
|
|
||||||
|
Commands:
|
||||||
|
generate-bash-completions Generate bash completions
|
||||||
|
generate-zsh-completions Generate zsh completions
|
||||||
|
generate-fish-completions Generate fish completions
|
||||||
|
grab-data Grabs the datasets used for benchmarking
|
||||||
|
benchmark Runs the benchmark
|
||||||
|
prep-dirs Prepares the directories so other programs can prepare their datasets
|
||||||
|
run Runs it all
|
||||||
|
help Print this message or the help of the given subcommand(s)
|
||||||
|
|
||||||
|
Options:
|
||||||
|
-h, --help Print help
|
||||||
|
-V, --version Print version
|
||||||
|
~> disk-read-benchmark generate-fish-completions | source
|
||||||
|
~> disk-read-benchmark benchmark --help
|
||||||
|
Runs the benchmark
|
||||||
|
|
||||||
|
Usage: disk-read-benchmark benchmark
|
||||||
|
|
||||||
|
Options:
|
||||||
|
-h, --help Print help
|
||||||
|
```
|
||||||
|
|
||||||
|
To better see how great it looks, here's a screenshot:
|
||||||
|
|
||||||
|
![The same output, but with very nice formatting - underlining and bolding for headers and the tables](/assets/using-clap/1.png)
|
||||||
|
|
||||||
|
Pressing tab twice after entering `disk-read-benchmark` displays the completions, which I can select and use like any other program's.
|
||||||
|
|
||||||
|
```txt
|
||||||
|
~> disk-read-benchmark
|
||||||
|
benchmark (Runs the benchmark) grab-data (Grabs the datasets used for benchmarking)
|
||||||
|
generate-bash-completions (Generate bash completions) help (Print this message or the help of the given subcommand(s))
|
||||||
|
generate-fish-completions (Generate fish completions) prep-dirs (Prepares the directories so other programs can prepare their datasets)
|
||||||
|
generate-zsh-completions (Generate zsh completions) run (Runs it all)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Sources
|
||||||
|
|
||||||
|
1. <https://docs.rs/clap/latest/clap/>
|
||||||
|
2. <https://docs.rs/clap_complete/latest/clap_complete/>
|
||||||
|
3. <https://github.com/clap-rs/clap/blob/master/clap_complete/examples/completion-derive.rs>
|
||||||
|
4. <https://github.com/rust-lang/cargo/blob/master/Cargo.toml>
|
||||||
|
5. <https://crates.io/crates/clap>
|
14
feed.xml
14
feed.xml
|
@ -5,10 +5,10 @@
|
||||||
<title>eng.askiiart.net</title>
|
<title>eng.askiiart.net</title>
|
||||||
<description>This is the feed for engl.askiiart.net, I guess</description>
|
<description>This is the feed for engl.askiiart.net, I guess</description>
|
||||||
<link>https://askiiart.net</link>
|
<link>https://askiiart.net</link>
|
||||||
<lastBuildDate>Fri, 04 Oct 2024 00:34:32 +0000</lastBuildDate>
|
<lastBuildDate>Tue, 12 Nov 2024 21:14:09 +0000</lastBuildDate>
|
||||||
<item>
|
<item>
|
||||||
<title>Checking out blendOS</title>
|
<title>Benchmarking and comparing DwarFS</title>
|
||||||
<link>https://engl.askiiart.net/blog/blendos.html</link>
|
<link>https://engl.askiiart.net/blog/benchmarking-dwarfs.html</link>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<title>Building blendOS (and its packages)</title>
|
<title>Building blendOS (and its packages)</title>
|
||||||
|
@ -18,6 +18,14 @@
|
||||||
<title>OCI Images as a "Filesystem": Vanilla OS</title>
|
<title>OCI Images as a "Filesystem": Vanilla OS</title>
|
||||||
<link>https://engl.askiiart.net/blog/vanilla-os.html</link>
|
<link>https://engl.askiiart.net/blog/vanilla-os.html</link>
|
||||||
</item>
|
</item>
|
||||||
|
<item>
|
||||||
|
<title>Checking out blendOS</title>
|
||||||
|
<link>https://engl.askiiart.net/blog/blendos.html</link>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<title>Using `clap`</title>
|
||||||
|
<link>https://engl.askiiart.net/blog/using-clap.html</link>
|
||||||
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<title>Glossary</title>
|
<title>Glossary</title>
|
||||||
<link>https://engl.askiiart.net/glossary.html</link>
|
<link>https://engl.askiiart.net/glossary.html</link>
|
||||||
|
|
|
@ -98,6 +98,8 @@
|
||||||
using FUSE). On Linux, device drivers are usually in the kernel
|
using FUSE). On Linux, device drivers are usually in the kernel
|
||||||
directly, rather than being installed separately like on
|
directly, rather than being installed separately like on
|
||||||
Windows.</li>
|
Windows.</li>
|
||||||
|
<li>Shell: The program which <em>is</em> the command-line
|
||||||
|
interface.</li>
|
||||||
</ul>
|
</ul>
|
||||||
<iframe src="https://john.citrons.xyz/embed?ref=askiiart.net" style="margin-left:auto;display:block;margin-right:auto;max-width:732px;width:100%;height:94px;border:none;"></iframe>
|
<iframe src="https://john.citrons.xyz/embed?ref=askiiart.net" style="margin-left:auto;display:block;margin-right:auto;max-width:732px;width:100%;height:94px;border:none;"></iframe>
|
||||||
<script src="/prism.js"></script>
|
<script src="/prism.js"></script>
|
||||||
|
|
|
@ -30,4 +30,5 @@
|
||||||
- `PKGBUILD`: A file defining how to build a package which can be install by `pacman`.
|
- `PKGBUILD`: A file defining how to build a package which can be install by `pacman`.
|
||||||
- `iso` file: A disk image file, can be "burned" to a USB flash drive (or any other disk) and booted off of, often used for Linux installers and/or live images.
|
- `iso` file: A disk image file, can be "burned" to a USB flash drive (or any other disk) and booted off of, often used for Linux installers and/or live images.
|
||||||
- FUSE: A filesystem interface used for running filesystems in userspace (i.e. not in the kernel)
|
- FUSE: A filesystem interface used for running filesystems in userspace (i.e. not in the kernel)
|
||||||
- Kernel: The very core of an operating system, with all its most essential functions, like filesystems (aside from those using FUSE). On Linux, device drivers are usually in the kernel directly, rather than being installed separately like on Windows.
|
- Kernel: The very core of an operating system, with all its most essential functions, like filesystems (aside from those using FUSE). On Linux, device drivers are usually in the kernel directly, rather than being installed separately like on Windows.
|
||||||
|
- Shell: The program which *is* the command-line interface.
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?><urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.sitemaps.org/schemas/sitemap/0.9 http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd">
|
<?xml version="1.0" encoding="UTF-8"?><urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.sitemaps.org/schemas/sitemap/0.9 http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd">
|
||||||
|
<url><loc>https://engl.askiiart.net/blog/using-clap.html</loc></url>
|
||||||
<url><loc>https://engl.askiiart.net/blog/blendos.html</loc></url>
|
<url><loc>https://engl.askiiart.net/blog/blendos.html</loc></url>
|
||||||
<url><loc>https://engl.askiiart.net/blog/building-blendos.html</loc></url>
|
<url><loc>https://engl.askiiart.net/blog/building-blendos.html</loc></url>
|
||||||
<url><loc>https://engl.askiiart.net/blog/vanilla-os.html</loc></url>
|
<url><loc>https://engl.askiiart.net/blog/vanilla-os.html</loc></url>
|
||||||
|
<url><loc>https://engl.askiiart.net/blog/benchmarking-dwarfs.html</loc></url>
|
||||||
<url><loc>https://engl.askiiart.net/glossary.html</loc></url>
|
<url><loc>https://engl.askiiart.net/glossary.html</loc></url>
|
||||||
<url><loc>https://engl.askiiart.net/index.html</loc></url>
|
<url><loc>https://engl.askiiart.net/index.html</loc></url>
|
||||||
<url><loc>https://engl.askiiart.net/about.html</loc></url>
|
<url><loc>https://engl.askiiart.net/about.html</loc></url>
|
||||||
|
|
|
@ -34,8 +34,7 @@ body {
|
||||||
}
|
}
|
||||||
|
|
||||||
li {
|
li {
|
||||||
font-family: 'Atkinson Hyperlegible';
|
font: 18px/1.35 'Atkinson Hyperlegible', sans-serif;}
|
||||||
}
|
|
||||||
|
|
||||||
p,
|
p,
|
||||||
footer {
|
footer {
|
||||||
|
|
Loading…
Reference in a new issue