qmk_firmware/assets/cli_development.md.C1RMbrqW.js

131 lines
27 KiB
JavaScript
Raw Normal View History

import { _ as _export_sfc, c as createElementBlock, o as openBlock, a8 as createStaticVNode, l as createBaseVNode, a as createTextVNode } from "./chunks/framework.B9AX-CPi.js";
const __pageData = JSON.parse('{"title":"QMK CLI Development","description":"","frontmatter":{},"headers":[],"relativePath":"cli_development.md","filePath":"cli_development.md"}');
const _sfc_main = { name: "cli_development.md" };
const _hoisted_1 = /* @__PURE__ */ createStaticVNode('<h1 id="qmk-cli-development" tabindex="-1">QMK CLI Development <a class="header-anchor" href="#qmk-cli-development" aria-label="Permalink to &quot;QMK CLI Development&quot;"></a></h1><p>This document has useful information for developers wishing to write new <code>qmk</code> subcommands.</p><h1 id="overview" tabindex="-1">Overview <a class="header-anchor" href="#overview" aria-label="Permalink to &quot;Overview&quot;"></a></h1><p>The QMK CLI operates using the subcommand pattern made famous by git. The main <code>qmk</code> script is simply there to setup the environment and pick the correct entrypoint to run. Each subcommand is a self-contained module with an entrypoint (decorated by <code>@cli.subcommand()</code>) that performs some action and returns a shell returncode, or None.</p><h2 id="developer-mode" tabindex="-1">Developer mode: <a class="header-anchor" href="#developer-mode" aria-label="Permalink to &quot;Developer mode:&quot;"></a></h2><p>If you intend to maintain keyboards and/or contribute to QMK, you can enable the CLI&#39;s &quot;Developer&quot; mode:</p><p><code>qmk config user.developer=True</code></p><p>This will allow you to see all available subcommands.<br><strong>Note:</strong> You will have to install additional requirements:</p><div class="language- vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang"></span><pre class="shiki shiki-themes github-light github-dark vp-code"><code><span class="line"><span>python3 -m pip install -r requirements-dev.txt</span></span></code></pre></div><h1 id="subcommands" tabindex="-1">Subcommands <a class="header-anchor" href="#subcommands" aria-label="Permalink to &quot;Subcommands&quot;"></a></h1><p><a href="https://github.com/clueboard/milc" target="_blank" rel="noreferrer">MILC</a> is the CLI framework <code>qmk</code> uses to handle argument parsing, configuration, logging, and many other features. It lets you focus on writing your tool without wasting your time writing glue code.</p><p>Subcommands in the local CLI are always found in <code>qmk_firmware/lib/python/qmk/cli</code>.</p><p>Let&#39;s start by looking at an example subcommand. This is <code>lib/python/qmk/cli/hello.py</code>:</p><div class="language-python vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">python</span><pre class="shiki shiki-themes github-light github-dark vp-code"><code><span class="line"><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">&quot;&quot;&quot;QMK Python Hello World</span></span>\n<span class="line"></span>\n<span class="line"><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">This is an example QMK CLI script.</span></span>\n<span class="line"><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">&quot;&quot;&quot;</span></span>\n<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">from</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> milc </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">import</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> cli</span></span>\n<span class="line"></span>\n<span class="line"></span>\n<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">@cli.argument</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">&#39;-n&#39;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">&#39;--name&#39;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, </span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;">default</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">&#39;World&#39;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, </span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;">help</span><span style="--shiki-light:#D73A49;--shi
const _hoisted_34 = /* @__PURE__ */ createBaseVNode("table", { fg_lightyellow_ex: "" }, [
/* @__PURE__ */ createBaseVNode("thead", null, [
/* @__PURE__ */ createBaseVNode("tr", null, [
/* @__PURE__ */ createBaseVNode("th", null, "Color"),
/* @__PURE__ */ createBaseVNode("th", null, "Background"),
/* @__PURE__ */ createBaseVNode("th", null, "Extended Background"),
/* @__PURE__ */ createBaseVNode("th", null, "Foreground"),
/* @__PURE__ */ createBaseVNode("th", null, "Extended Foreground")
])
]),
/* @__PURE__ */ createBaseVNode("tbody", null, [
/* @__PURE__ */ createBaseVNode("tr", { fg_lightblack_ex: "" }, [
/* @__PURE__ */ createBaseVNode("td", null, "Black"),
/* @__PURE__ */ createBaseVNode("td", { bg_black: "" }),
/* @__PURE__ */ createBaseVNode("td", { bg_lightblack_ex: "" }),
/* @__PURE__ */ createBaseVNode("td", { fg_black: "" }),
/* @__PURE__ */ createBaseVNode("td")
]),
/* @__PURE__ */ createBaseVNode("tr", { fg_lightblue_ex: "" }, [
/* @__PURE__ */ createBaseVNode("td", null, "Blue"),
/* @__PURE__ */ createBaseVNode("td", { bg_blue: "" }),
/* @__PURE__ */ createBaseVNode("td", { bg_lightblue_ex: "" }),
/* @__PURE__ */ createBaseVNode("td", { fg_blue: "" }),
/* @__PURE__ */ createBaseVNode("td")
]),
/* @__PURE__ */ createBaseVNode("tr", { fg_lightcyan_ex: "" }, [
/* @__PURE__ */ createBaseVNode("td", null, "Cyan"),
/* @__PURE__ */ createBaseVNode("td", { bg_cyan: "" }),
/* @__PURE__ */ createBaseVNode("td", { bg_lightcyan_ex: "" }),
/* @__PURE__ */ createBaseVNode("td", { fg_cyan: "" }),
/* @__PURE__ */ createBaseVNode("td")
]),
/* @__PURE__ */ createBaseVNode("tr", { fg_lightgreen_ex: "" }, [
/* @__PURE__ */ createBaseVNode("td", null, "Green"),
/* @__PURE__ */ createBaseVNode("td", { bg_green: "" }),
/* @__PURE__ */ createBaseVNode("td", { bg_lightgreen_ex: "" }),
/* @__PURE__ */ createBaseVNode("td", { fg_green: "" }),
/* @__PURE__ */ createBaseVNode("td")
]),
/* @__PURE__ */ createBaseVNode("tr", { fg_lightmagenta_ex: "" }, [
/* @__PURE__ */ createBaseVNode("td", null, "Magenta"),
/* @__PURE__ */ createBaseVNode("td", { bg_magenta: "" }),
/* @__PURE__ */ createBaseVNode("td", { bg_lightmagenta_ex: "" }),
/* @__PURE__ */ createBaseVNode("td", { fg_magenta: "" }),
/* @__PURE__ */ createBaseVNode("td")
]),
/* @__PURE__ */ createBaseVNode("tr", { fg_lightred_ex: "" }, [
/* @__PURE__ */ createBaseVNode("td", null, "Red"),
/* @__PURE__ */ createBaseVNode("td", { bg_red: "" }),
/* @__PURE__ */ createBaseVNode("td", { bg_lightred_ex: "" }),
/* @__PURE__ */ createBaseVNode("td", { fg_red: "" }),
/* @__PURE__ */ createBaseVNode("td")
]),
/* @__PURE__ */ createBaseVNode("tr", { fg_lightwhite_ex: "" }, [
/* @__PURE__ */ createBaseVNode("td", null, "White"),
/* @__PURE__ */ createBaseVNode("td", { bg_white: "" }),
/* @__PURE__ */ createBaseVNode("td", { bg_lightwhite_ex: "" }),
/* @__PURE__ */ createBaseVNode("td", { fg_white: "" }),
/* @__PURE__ */ createBaseVNode("td")
]),
/* @__PURE__ */ createBaseVNode("tr", null, [
/* @__PURE__ */ createBaseVNode("td", null, "Yellow"),
/* @__PURE__ */ createBaseVNode("td", { bg_yellow: "" }),
/* @__PURE__ */ createBaseVNode("td", { bg_lightyellow_ex: "" }),
/* @__PURE__ */ createBaseVNode("td", { fg_yellow: "" }),
/* @__PURE__ */ createBaseVNode("td")
])
])
], -1);
const _hoisted_35 = /* @__PURE__ */ createBaseVNode("p", null, "There are also control sequences that can be used to change the behavior of ANSI output:", -1);
const _hoisted_36 = /* @__PURE__ */ createBaseVNode("table", null, [
/* @__PURE__ */ createBaseVNode("thead", null, [
/* @__PURE__ */ createBaseVNode("tr", null, [
/* @__PURE__ */ createBaseVNode("th", null, "Control Sequences"),
/* @__PURE__ */ createBaseVNode("th", null, "Description")
])
]),
/* @__PURE__ */ createBaseVNode("tbody", null, [
/* @__PURE__ */ createBaseVNode("tr", null, [
/* @__PURE__ */ createBaseVNode("td", { style_bright: "" }),
/* @__PURE__ */ createBaseVNode("td", null, "Make the text brighter")
]),
/* @__PURE__ */ createBaseVNode("tr", null, [
/* @__PURE__ */ createBaseVNode("td", { style_dim: "" }),
/* @__PURE__ */ createBaseVNode("td", null, "Make the text dimmer")
]),
/* @__PURE__ */ createBaseVNode("tr", null, [
/* @__PURE__ */ createBaseVNode("td", { style_normal: "" }),
/* @__PURE__ */ createBaseVNode("td", null, [
/* @__PURE__ */ createTextVNode("Make the text normal (neither "),
/* @__PURE__ */ createBaseVNode("code", null, "{style_bright}"),
/* @__PURE__ */ createTextVNode(" nor "),
/* @__PURE__ */ createBaseVNode("code", null, "{style_dim}"),
/* @__PURE__ */ createTextVNode(")")
])
]),
/* @__PURE__ */ createBaseVNode("tr", null, [
/* @__PURE__ */ createBaseVNode("td", { style_reset_all: "" }),
/* @__PURE__ */ createBaseVNode("td", null, "Reset all text attributes to default. (This is automatically added to the end of every string.)")
]),
/* @__PURE__ */ createBaseVNode("tr", null, [
/* @__PURE__ */ createBaseVNode("td", { bg_reset: "" }),
/* @__PURE__ */ createBaseVNode("td", null, "Reset the background color to the user's default")
]),
/* @__PURE__ */ createBaseVNode("tr", null, [
/* @__PURE__ */ createBaseVNode("td", { fg_reset: "" }),
/* @__PURE__ */ createBaseVNode("td", null, "Reset the foreground color to the user's default")
])
])
], -1);
const _hoisted_37 = /* @__PURE__ */ createStaticVNode('<h1 id="arguments-and-configuration" tabindex="-1">Arguments and Configuration <a class="header-anchor" href="#arguments-and-configuration" aria-label="Permalink to &quot;Arguments and Configuration&quot;"></a></h1><p>QMK handles the details of argument parsing and configuration for you. When you add a new argument it is automatically incorporated into the config tree based on your subcommand&#39;s name and the long name of the argument. You can access this configuration in <code>cli.config</code>, using either attribute-style access (<code>cli.config.&lt;subcommand&gt;.&lt;argument&gt;</code>) or dictionary-style access (<code>cli.config[&#39;&lt;subcommand&gt;&#39;][&#39;&lt;argument&gt;&#39;]</code>).</p><p>Under the hood QMK uses <a href="https://docs.python.org/3/library/configparser.html" target="_blank" rel="noreferrer">ConfigParser</a> to store configurations. This gives us an easy and straightforward way to represent the configuration in a human-editable way. We have wrapped access to this configuration to provide some nicities that ConfigParser does not normally have.</p><h2 id="reading-configuration-values" tabindex="-1">Reading Configuration Values <a class="header-anchor" href="#reading-configuration-values" aria-label="Permalink to &quot;Reading Configuration Values&quot;"></a></h2><p>You can interact with <code>cli.config</code> in all the ways you&#39;d normally expect. For example the <code>qmk compile</code> command gets the keyboard name from <code>cli.config.compile.keyboard</code>. It does not need to know whether that value came from the command line, an environment variable, or the configuration file.</p><p>Iteration is also supported:</p><div class="language- vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang"></span><pre class="shiki shiki-themes github-light github-dark vp-code"><code><span class="line"><span>for section in cli.config:</span></span>\n<span class="line"><span> for key in cli.config[section]:</span></span>\n<span class="line"><span> cli.log.info(&#39;%s.%s: %s&#39;, section, key, cli.config[section][key])</span></span></code></pre></div><h2 id="setting-configuration-values" tabindex="-1">Setting Configuration Values <a class="header-anchor" href="#setting-configuration-values" aria-label="Permalink to &quot;Setting Configuration Values&quot;"></a></h2><p>You can set configuration values in the usual ways.</p><p>Dictionary style:</p><div class="language- vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang"></span><pre class="shiki shiki-themes github-light github-dark vp-code"><code><span class="line"><span>cli.config[&#39;&lt;section&gt;&#39;][&#39;&lt;key&gt;&#39;] = &lt;value&gt;</span></span></code></pre></div><p>Attribute style:</p><div class="language- vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang"></span><pre class="shiki shiki-themes github-light github-dark vp-code"><code><span class="line"><span>cli.config.&lt;section&gt;.&lt;key&gt; = &lt;value&gt;</span></span></code></pre></div><h2 id="deleting-configuration-values" tabindex="-1">Deleting Configuration Values <a class="header-anchor" href="#deleting-configuration-values" aria-label="Permalink to &quot;Deleting Configuration Values&quot;"></a></h2><p>You can delete configuration values in the usual ways.</p><p>Dictionary style:</p><div class="language- vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang"></span><pre class="shiki shiki-themes github-light github-dark vp-code"><code><span class="line"><span>del(cli.config[&#39;&lt;section&gt;&#39;][&#39;&lt;key&gt;&#39;])</span></span></code></pre></div><p>Attribute style:</p><div class="language- vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang"></span><pre class="shiki shiki-themes github-light github-dark vp-code"><code><span class="line"><span>del(cli.config.&lt;section&gt;.&lt;key&gt;)</span></span></code></pre></div><
const _hoisted_81 = [
_hoisted_1,
_hoisted_34,
_hoisted_35,
_hoisted_36,
_hoisted_37
];
function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) {
return openBlock(), createElementBlock("div", null, _hoisted_81);
}
const cli_development = /* @__PURE__ */ _export_sfc(_sfc_main, [["render", _sfc_render]]);
export {
__pageData,
cli_development as default
};