<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: MoniqueLive</title>
    <description>The latest articles on DEV Community by MoniqueLive (@moniquelive).</description>
    <link>https://dev.to/moniquelive</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.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F74371%2Fcad23d83-2883-4551-b20d-e2ec02085918.jpg</url>
      <title>DEV Community: MoniqueLive</title>
      <link>https://dev.to/moniquelive</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/moniquelive"/>
    <language>en</language>
    <item>
      <title>I love discoverability...</title>
      <dc:creator>MoniqueLive</dc:creator>
      <pubDate>Fri, 05 Jun 2026 20:01:33 +0000</pubDate>
      <link>https://dev.to/moniquelive/i-love-discoverability-17ip</link>
      <guid>https://dev.to/moniquelive/i-love-discoverability-17ip</guid>
      <description>&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/moniquelive/finding-man-pages-from-neovim-with-telescope-andor-minipick-4cm0" class="crayons-story__hidden-navigation-link"&gt;Finding man pages from Neovim with Telescope and/or mini.pick&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;

          &lt;a href="/moniquelive" class="crayons-avatar  crayons-avatar--l  "&gt;
            &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F74371%2Fcad23d83-2883-4551-b20d-e2ec02085918.jpg" alt="moniquelive profile" class="crayons-avatar__image"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/moniquelive" class="crayons-story__secondary fw-medium m:hidden"&gt;
              MoniqueLive
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                MoniqueLive
                
              
              &lt;div id="story-author-preview-content-3830269" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/moniquelive" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&gt;
                        &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F74371%2Fcad23d83-2883-4551-b20d-e2ec02085918.jpg" class="crayons-avatar__image" alt=""&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;MoniqueLive&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

          &lt;/div&gt;
          &lt;a href="https://dev.to/moniquelive/finding-man-pages-from-neovim-with-telescope-andor-minipick-4cm0" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;Jun 5&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/moniquelive/finding-man-pages-from-neovim-with-telescope-andor-minipick-4cm0" id="article-link-3830269"&gt;
          Finding man pages from Neovim with Telescope and/or mini.pick
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/neovim"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;neovim&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/lua"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;lua&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/telescope"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;telescope&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/vim"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;vim&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
            &lt;a href="https://dev.to/moniquelive/finding-man-pages-from-neovim-with-telescope-andor-minipick-4cm0#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              

              &lt;span class="hidden s:inline"&gt;Add&amp;nbsp;Comment&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            4 min read
          &lt;/small&gt;
            
              &lt;span class="bm-initial crayons-icon c-btn__icon"&gt;
                

              &lt;/span&gt;
              &lt;span class="bm-success crayons-icon c-btn__icon"&gt;
                

              &lt;/span&gt;
            
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;


</description>
    </item>
    <item>
      <title>Finding man pages from Neovim with Telescope and/or mini.pick</title>
      <dc:creator>MoniqueLive</dc:creator>
      <pubDate>Fri, 05 Jun 2026 19:58:41 +0000</pubDate>
      <link>https://dev.to/moniquelive/finding-man-pages-from-neovim-with-telescope-andor-minipick-4cm0</link>
      <guid>https://dev.to/moniquelive/finding-man-pages-from-neovim-with-telescope-andor-minipick-4cm0</guid>
      <description>&lt;p&gt;I use man pages all the time, but sometimes I do not know exactly what I want to open.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;printf&lt;/code&gt; is a good example.&lt;/p&gt;

&lt;p&gt;There is &lt;code&gt;printf(1)&lt;/code&gt; for the shell command, &lt;code&gt;printf(3)&lt;/code&gt; for the C library function, and depending on what is installed locally there may be even more entries around it.&lt;/p&gt;

&lt;p&gt;I wanted something simple inside Neovim:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;list local man pages&lt;/li&gt;
&lt;li&gt;fuzzy search them&lt;/li&gt;
&lt;li&gt;see the section before opening&lt;/li&gt;
&lt;li&gt;open using Neovim's built-in &lt;code&gt;:Man&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So I made a small plugin: &lt;code&gt;man.nvim&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Source:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;GitHub: &lt;a href="https://github.com/moniquelive/man.nvim" rel="noopener noreferrer"&gt;https://github.com/moniquelive/man.nvim&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What it does
&lt;/h2&gt;

&lt;p&gt;The plugin starts with the system database:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;apropos &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then it parses the output into picker items like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[1 User commands] printf(1) - format and print data
[3 Library calls] printf(3) - formatted output conversion
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The important part is that selecting an entry still delegates to Neovim:&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;Man &lt;span class="m"&gt;3&lt;/span&gt; &lt;span class="nb"&gt;printf&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No custom renderer.&lt;br&gt;
No terminal buffer pretending to be man.&lt;br&gt;
No reimplementing man page navigation.&lt;/p&gt;

&lt;p&gt;Just discovery through a picker, opening through &lt;code&gt;:Man&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  Why not just use :Man?
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;:Man&lt;/code&gt; is great once I know what I want.&lt;/p&gt;

&lt;p&gt;But I often want to explore what is installed locally. I may remember part of the name, or the description, or the section.&lt;/p&gt;

&lt;p&gt;With the picker I can type things like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;printf
3 printf
formatted output
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And the item text includes the section label, so it is easy to see if I am about to open the command, library call, file format, etc.&lt;/p&gt;

&lt;h2&gt;
  
  
  Telescope version
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;main&lt;/code&gt; branch exposes a Telescope extension.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight lua"&gt;&lt;code&gt;&lt;span class="nb"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'telescope'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;setup&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="nb"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'man_nvim'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;setup&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Usage:&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;Telescope man
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Internally it uses a table finder. Each parsed man page becomes an entry with data like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight lua"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'printf'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;section&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'3'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;ref&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'printf(3)'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;description&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'formatted output conversion'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The display and ordinal use the same searchable text:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight lua"&gt;&lt;code&gt;&lt;span class="s1"&gt;'[3 Library calls] printf(3) - formatted output conversion'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That keeps Telescope doing what Telescope is good at: prompt, sorting, preview, mappings.&lt;/p&gt;

&lt;h2&gt;
  
  
  mini.pick version
&lt;/h2&gt;

&lt;p&gt;There is also a &lt;code&gt;mini.picker&lt;/code&gt; branch using &lt;code&gt;mini.pick&lt;/code&gt;.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight lua"&gt;&lt;code&gt;&lt;span class="nb"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'mini.pick'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;setup&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="nb"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'man_nvim'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;setup&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Usage:&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;Pick man
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The interesting part is that most of the plugin is shared conceptually:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;parse &lt;code&gt;apropos&lt;/code&gt; output&lt;/li&gt;
&lt;li&gt;split aliases&lt;/li&gt;
&lt;li&gt;sort by man section&lt;/li&gt;
&lt;li&gt;build the &lt;code&gt;:Man&lt;/code&gt; command&lt;/li&gt;
&lt;li&gt;show a small preview&lt;/li&gt;
&lt;li&gt;open the selected page&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Only the picker integration changes.&lt;/p&gt;

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

&lt;p&gt;Some apropos entries have a lot of aliases.&lt;/p&gt;

&lt;p&gt;For example, shells can produce lines like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;builtin(1), !(1), %(1), .(1), :(1), [(1) - shell built-in commands
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The plugin creates searchable items for the aliases, but opens the canonical page.&lt;/p&gt;

&lt;p&gt;So if I search for &lt;code&gt;!&lt;/code&gt;, I can find &lt;code&gt;!(1)&lt;/code&gt;, but selecting it opens &lt;code&gt;builtin(1)&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;That matters because some aliases are not real standalone man pages. They are documented under the first entry in that apropos line.&lt;/p&gt;

&lt;h2&gt;
  
  
  Filtering noisy results
&lt;/h2&gt;

&lt;p&gt;One thing that got annoying very quickly: Tcl/Tk results.&lt;/p&gt;

&lt;p&gt;Sometimes a search like &lt;code&gt;format&lt;/code&gt; shows useful results, but also a bunch of Tcl-related entries that I do not care about at that moment.&lt;/p&gt;

&lt;p&gt;So I added negative prompt terms.&lt;/p&gt;

&lt;p&gt;In both Telescope and mini.pick versions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;format -tcl
format -tcl -tk
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This means:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;search for &lt;code&gt;format&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;exclude entries containing &lt;code&gt;tcl&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;optionally also exclude &lt;code&gt;tk&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The negative terms use smartcase too:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;-tcl  # excludes tcl, Tcl, TCL, etc when smartcase allows it
-Tcl  # case-sensitive exclusion
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The Telescope version implements this as a sorter wrapper. It removes the negative terms from the prompt, filters entries, then delegates the positive query back to Telescope's normal sorter.&lt;/p&gt;

&lt;p&gt;The mini.pick version implements this as a custom &lt;code&gt;source.match&lt;/code&gt;. It filters entries first, then passes the positive query back into &lt;code&gt;MiniPick.default_match&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;That way I keep each picker's normal matching behavior instead of replacing it with my own fuzzy matcher.&lt;/p&gt;

&lt;h2&gt;
  
  
  Opening mappings
&lt;/h2&gt;

&lt;p&gt;The mappings are intentionally boring:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;CR&amp;gt;  :vertical Man {section} {name}
&amp;lt;C-x&amp;gt; :Man {section} {name}
&amp;lt;C-v&amp;gt; :vertical Man {section} {name}
&amp;lt;C-t&amp;gt; :tab Man {section} {name}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;&amp;lt;CR&amp;gt;&lt;/code&gt; opens vertically by default because that is how I usually want docs next to code.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&amp;lt;C-x&amp;gt;&lt;/code&gt; opens with regular &lt;code&gt;:Man&lt;/code&gt; for the classic horizontal split habit.&lt;/p&gt;

&lt;h2&gt;
  
  
  Portability notes
&lt;/h2&gt;

&lt;p&gt;The plugin is meant to work on macOS, Linux, and FreeBSD.&lt;/p&gt;

&lt;p&gt;That mostly means avoiding clever assumptions.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;apropos&lt;/code&gt; output can be noisy. On my macOS machine I saw lines like &lt;code&gt;makewhatis: ... No such file or directory&lt;/code&gt;, so the parser simply ignores lines that do not look like man entries.&lt;/p&gt;

&lt;p&gt;Sections are also not always just &lt;code&gt;1&lt;/code&gt; through &lt;code&gt;9&lt;/code&gt;. There can be things like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;3p
3posix
n
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So the parser accepts section names inside parentheses instead of assuming one digit.&lt;/p&gt;

&lt;p&gt;For opening pages, the plugin lets Neovim and the system &lt;code&gt;man&lt;/code&gt; command handle the hard part.&lt;/p&gt;

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

&lt;p&gt;With &lt;a href="https://github.com/folke/lazy.nvim" rel="noopener noreferrer"&gt;lazy.nvim&lt;/a&gt;, for the Telescope version:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight lua"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="s1"&gt;'moniquelive/man.nvim'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;dependencies&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s1"&gt;'nvim-telescope/telescope.nvim'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="n"&gt;config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="nb"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'man_nvim'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;setup&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For the &lt;code&gt;mini.pick&lt;/code&gt; version:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight lua"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="s1"&gt;'moniquelive/man.nvim'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;branch&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'mini.picker'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;dependencies&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s1"&gt;'echasnovski/mini.pick'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="n"&gt;config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="nb"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'mini.pick'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;setup&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="nb"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'man_nvim'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;setup&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With &lt;a href="https://github.com/wbthomason/packer.nvim" rel="noopener noreferrer"&gt;packer.nvim&lt;/a&gt;, for Telescope:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight lua"&gt;&lt;code&gt;&lt;span class="n"&gt;use&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="s1"&gt;'moniquelive/man.nvim'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;requires&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s1"&gt;'nvim-telescope/telescope.nvim'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="n"&gt;config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="nb"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'man_nvim'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;setup&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For &lt;code&gt;mini.pick&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight lua"&gt;&lt;code&gt;&lt;span class="n"&gt;use&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="s1"&gt;'moniquelive/man.nvim'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;branch&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'mini.picker'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;requires&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s1"&gt;'echasnovski/mini.pick'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="n"&gt;config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="nb"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'mini.pick'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;setup&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="nb"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'man_nvim'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;setup&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With &lt;a href="https://github.com/junegunn/vim-plug" rel="noopener noreferrer"&gt;vim-plug&lt;/a&gt;, for Telescope:&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;'nvim-telescope/telescope.nvim'&lt;/span&gt;
Plug &lt;span class="s1"&gt;'moniquelive/man.nvim'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then somewhere after plugins load:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight lua"&gt;&lt;code&gt;&lt;span class="nb"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'man_nvim'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;setup&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For &lt;code&gt;mini.pick&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;Plug &lt;span class="s1"&gt;'echasnovski/mini.pick'&lt;/span&gt;
Plug &lt;span class="s1"&gt;'moniquelive/man.nvim'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s1"&gt;'branch'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'mini.picker'&lt;/span&gt; &lt;span class="p"&gt;}&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 lua"&gt;&lt;code&gt;&lt;span class="nb"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'mini.pick'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;setup&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="nb"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'man_nvim'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;setup&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Final thoughts
&lt;/h2&gt;

&lt;p&gt;This is a small plugin, but it fits my workflow nicely.&lt;/p&gt;

&lt;p&gt;I did not want to replace &lt;code&gt;man&lt;/code&gt;.&lt;br&gt;
I only wanted a better way to discover local man pages from inside Neovim.&lt;/p&gt;

&lt;p&gt;Telescope and mini.pick both work well for this. The fun part was keeping the core behavior simple, and only changing the picker layer.&lt;/p&gt;

&lt;p&gt;If I extend this next, I may add a filesystem fallback for machines where the &lt;code&gt;apropos&lt;/code&gt; database is missing or stale.&lt;/p&gt;

&lt;p&gt;But for now: fuzzy search local docs, filter away noise, open with &lt;code&gt;:Man&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Profit!&lt;/p&gt;

</description>
      <category>neovim</category>
      <category>lua</category>
      <category>telescope</category>
      <category>vim</category>
    </item>
    <item>
      <title>Integrating my AVR with Home Assistant</title>
      <dc:creator>MoniqueLive</dc:creator>
      <pubDate>Mon, 30 Mar 2026 20:53:21 +0000</pubDate>
      <link>https://dev.to/moniquelive/integrating-my-avr-with-home-assistant-3oio</link>
      <guid>https://dev.to/moniquelive/integrating-my-avr-with-home-assistant-3oio</guid>
      <description>&lt;p&gt;I was tired of digging through tiny on-device menus just to turn Zone 2 on and off on my AVR.&lt;/p&gt;

&lt;p&gt;So I built a small Go CLI (&lt;code&gt;zone2&lt;/code&gt;) that talks directly to the receiver over WebSocket, then wired it into Home Assistant as a &lt;code&gt;command_line&lt;/code&gt; switch.&lt;/p&gt;

&lt;p&gt;If you have an Arcam / AudioControl / JBL Synthesis receiver that exposes the setup WebSocket API on port &lt;code&gt;50001&lt;/code&gt;, this approach is straightforward and fast.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://github.com/moniquelive/zone2" rel="noopener noreferrer"&gt;Source code&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Why I chose a CLI first
&lt;/h2&gt;

&lt;p&gt;Instead of jumping straight into a custom Home Assistant integration, I wanted a simple binary that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;can run anywhere&lt;/li&gt;
&lt;li&gt;is easy to test from terminal&lt;/li&gt;
&lt;li&gt;returns plain &lt;code&gt;on&lt;/code&gt; / &lt;code&gt;off&lt;/code&gt; output for automation parsing&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That gave me a stable foundation before touching dashboards and YAML.&lt;/p&gt;

&lt;h2&gt;
  
  
  How the AVR communication works
&lt;/h2&gt;

&lt;p&gt;The tool connects to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;ws://&amp;lt;AVR_IP&amp;gt;:50001&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It sends binary protocol frames for Zone 2 (&lt;code&gt;command 0x2F&lt;/code&gt;), then parses binary responses from the AVR.&lt;/p&gt;

&lt;p&gt;Frame format (simplified):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;request:  21 01 &amp;lt;command&amp;gt; &amp;lt;len&amp;gt; &amp;lt;payload...&amp;gt; 0D
response: 21 01 &amp;lt;command&amp;gt; &amp;lt;status&amp;gt; &amp;lt;len&amp;gt; &amp;lt;payload...&amp;gt; 0D
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For reads, it queries the Zone 2 model and inspects the second byte (&lt;code&gt;model[1]&lt;/code&gt;) as power state:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;0&lt;/code&gt; =&amp;gt; off&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;1&lt;/code&gt; =&amp;gt; on&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For writes (&lt;code&gt;on&lt;/code&gt;, &lt;code&gt;off&lt;/code&gt;, &lt;code&gt;toggle&lt;/code&gt;), it updates that byte and sends the full model back.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reliability changes that mattered
&lt;/h2&gt;

&lt;p&gt;The hard part was not "sending commands", it was making behavior reliable enough for automations.&lt;/p&gt;

&lt;p&gt;I added a few guardrails:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Frame splitting&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Receivers can send multiple protocol frames in a single WebSocket message.&lt;/li&gt;
&lt;li&gt;The client extracts valid frames by header/length/terminator and picks the right command.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Strict response parsing&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Validates framing, command ID, terminator, and declared payload length.&lt;/li&gt;
&lt;li&gt;Rejects malformed frames early.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Retry on transient states&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Zone 2 query retries up to 5 times.&lt;/li&gt;
&lt;li&gt;Handles temporary &lt;code&gt;0x85&lt;/code&gt; status by waiting briefly and retrying.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Post-write verification loop&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;After a write, it re-queries state until the target sticks (default &lt;code&gt;20&lt;/code&gt; attempts).&lt;/li&gt;
&lt;li&gt;This avoids false positives where a write ACK arrives but state does not actually change.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This is what made it usable from Home Assistant without random "it worked... I think?" moments.&lt;/p&gt;

&lt;h2&gt;
  
  
  CLI usage
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;./zone2-macos-arm64 &lt;span class="nt"&gt;-host&lt;/span&gt; YOUR_AVR_IP &lt;span class="nt"&gt;-mode&lt;/span&gt; status
./zone2-macos-arm64 &lt;span class="nt"&gt;-host&lt;/span&gt; YOUR_AVR_IP &lt;span class="nt"&gt;-mode&lt;/span&gt; on
./zone2-macos-arm64 &lt;span class="nt"&gt;-host&lt;/span&gt; YOUR_AVR_IP &lt;span class="nt"&gt;-mode&lt;/span&gt; off
./zone2-macos-arm64 &lt;span class="nt"&gt;-host&lt;/span&gt; YOUR_AVR_IP &lt;span class="nt"&gt;-mode&lt;/span&gt; toggle
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Flags:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;-host&lt;/code&gt; (required)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-mode&lt;/code&gt; (&lt;code&gt;on|off|toggle|status&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-timeout&lt;/code&gt; (default &lt;code&gt;4s&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-verify&lt;/code&gt; (default &lt;code&gt;20&lt;/code&gt;, used for writes)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-verbose&lt;/code&gt; (prints raw TX/RX frames)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Home Assistant integration
&lt;/h2&gt;

&lt;p&gt;I cross-compile a Linux ARM64 binary for HA OS (Raspberry Pi 5), copy it into &lt;code&gt;/config/bin&lt;/code&gt;, and expose it via &lt;code&gt;command_line&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;command_line&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;switch&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;AVR Zone &lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;
      &lt;span class="na"&gt;unique_id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;avr_zone2&lt;/span&gt;
      &lt;span class="na"&gt;command_on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/config/bin/zone2&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;-host&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;YOUR_AVR_IP&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;-mode&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;on&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;-timeout&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;4s&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;-verify&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;20"&lt;/span&gt;
      &lt;span class="na"&gt;command_off&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/config/bin/zone2&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;-host&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;YOUR_AVR_IP&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;-mode&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;off&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;-timeout&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;4s&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;-verify&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;20"&lt;/span&gt;
      &lt;span class="na"&gt;command_state&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/config/bin/zone2&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;-host&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;YOUR_AVR_IP&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;-mode&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;status&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;-timeout&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;4s"&lt;/span&gt;
      &lt;span class="na"&gt;value_template&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;{{&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;value&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;|&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;trim&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;|&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;lower&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;==&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;'on'&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;}}"&lt;/span&gt;
      &lt;span class="na"&gt;scan_interval&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Because the CLI prints exactly &lt;code&gt;on&lt;/code&gt; or &lt;code&gt;off&lt;/code&gt;, the value template stays simple and reliable.&lt;/p&gt;

&lt;h2&gt;
  
  
  Build + release flow
&lt;/h2&gt;

&lt;p&gt;The repo includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Makefile targets for Linux ARM64 + macOS binaries&lt;/li&gt;
&lt;li&gt;CI (&lt;code&gt;go test&lt;/code&gt;, &lt;code&gt;go vet&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;tag-triggered GitHub release workflow attaching compiled binaries&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That made it easy to test locally and deploy repeatably.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final thoughts
&lt;/h2&gt;

&lt;p&gt;This was a small project, but a useful reminder: in home automation, &lt;strong&gt;state verification&lt;/strong&gt; is more important than "command sent successfully".&lt;/p&gt;

&lt;p&gt;A tiny, deterministic CLI with clear output is often enough to bridge unsupported hardware into Home Assistant cleanly.&lt;/p&gt;

&lt;p&gt;If I extend this next, I'll likely add controls for input/volume and package a full HA integration once the protocol surface is mature.&lt;/p&gt;

</description>
      <category>homeassistant</category>
      <category>go</category>
      <category>websocket</category>
      <category>smarthome</category>
    </item>
    <item>
      <title>Tech Meets Tunes: Creating a Seamless Alfred Workflow for EDM Aficionados</title>
      <dc:creator>MoniqueLive</dc:creator>
      <pubDate>Fri, 05 Jan 2024 18:54:46 +0000</pubDate>
      <link>https://dev.to/moniquelive/tech-meets-tunes-creating-a-seamless-alfred-workflow-for-edm-aficionados-1fhi</link>
      <guid>https://dev.to/moniquelive/tech-meets-tunes-creating-a-seamless-alfred-workflow-for-edm-aficionados-1fhi</guid>
      <description>&lt;h3&gt;
  
  
  The Problem
&lt;/h3&gt;

&lt;p&gt;If you're a EDM fan like me you probably know the super traditional website &lt;a href="https://di.fm" rel="noopener noreferrer"&gt;Digitally Imported&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I'm a long time supporter (and I recommend you consider supporting it - streaming bills ain't cheap ya know). But one thing bugged me for a long time: it has no native player like Spotify and Apple Music. And I like changing stations all day long. And I don't like keeping a browser tab exclusively for this.&lt;/p&gt;

&lt;p&gt;Since I'm a heavy Alfred user I looked for a workflow but had no luck. So I made one.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Solution
&lt;/h3&gt;

&lt;p&gt;The workflow editor is pretty neat. You drop boxes and link them in order to make one box's output become the other's input:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4h6d9yvzfkbk3losdov9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4h6d9yvzfkbk3losdov9.png" alt="My Alfred's Workflow panel" width="800" height="446"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;My Alfred's Workflow panel&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;And that's it. Just two boxes linked in order to play some electronic music ❤️ &lt;/p&gt;
&lt;h3&gt;
  
  
  But wait, there's more!
&lt;/h3&gt;

&lt;p&gt;It would be a very boring article if it ended here, right? 😊 &lt;br&gt;
First of all, the list of radio stations is huge! (99):&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnb20ohcdidm57m9b5xzu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnb20ohcdidm57m9b5xzu.png" alt="double clicking on List Filter" width="799" height="579"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;double clicking on List Filter&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I would never type 99 times each station information... No... I asked our friendly overlord &lt;strong&gt;GPT-4&lt;/strong&gt; for some help.&lt;/p&gt;
&lt;h3&gt;
  
  
  Chat GPT to the rescue
&lt;/h3&gt;

&lt;p&gt;All I had was the 99 url slugs for each radio station. When you open a playlist (.pls file) you'll get all the streaming url's in the form:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;http://prem1.di.fm/${query}?XXXXXX&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Where &lt;code&gt;${query}&lt;/code&gt; is the station name and &lt;code&gt;XXXX&lt;/code&gt; is your 'Listen key' that can be grabbed on the &lt;a href="https://www.di.fm/settings" rel="noopener noreferrer"&gt;Settings&lt;/a&gt; page.&lt;/p&gt;

&lt;p&gt;But in order to fill the workflow's &lt;em&gt;List Filter&lt;/em&gt; I needed a .csv file with 3 columns:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;First some words, separated by space, which are searched after you type your workflow's keyword&lt;/li&gt;
&lt;li&gt;A plain text english description that will be shown as a subtitle&lt;/li&gt;
&lt;li&gt;The value that will be passed as the input for the next node on the graph&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;So the prompt I wrote was basically:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;Given the following slugs:
&lt;span class="p"&gt;
-&lt;/span&gt; 00sclubhits
&lt;span class="p"&gt;-&lt;/span&gt; ambient
&lt;span class="p"&gt;-&lt;/span&gt; atmosphericbreaks
... (until 99)

Create a three column CSV formatted list of:
&lt;span class="p"&gt;
-&lt;/span&gt; the slug broken in words
&lt;span class="p"&gt;-&lt;/span&gt; a plain english description of the slug
&lt;span class="p"&gt;-&lt;/span&gt; the slug unchanged

For example:
&lt;span class="p"&gt;
-&lt;/span&gt; 00sclubhits

in CSV:

00s club hits, 2000's Club Hits, 00sclubhits
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And it very kindly generated &lt;a href="https://gist.github.com/moniquelive/bee80daafd5fb6658e8f3baa5419df57" rel="noopener noreferrer"&gt;this csv file&lt;/a&gt;. ❤️ (full disclosure: I removed the header line and removed extra spaces between columns that confused Alfred)&lt;/p&gt;

&lt;p&gt;Then I dragged the generated .csv file into the left column of the &lt;em&gt;List Filter&lt;/em&gt; and that was it for this node.&lt;/p&gt;

&lt;p&gt;The second node is super simple. It's a &lt;em&gt;Run Script&lt;/em&gt; node with the following:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmf69tbqw5z6ryuzqfnqf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmf69tbqw5z6ryuzqfnqf.png" alt="Open Apple Music with the following url" width="800" height="579"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Open Apple Music with the following url&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;You can use your preferred player here. I tested with VLC and Apple Music.&lt;/p&gt;

&lt;h3&gt;
  
  
  And that's it!
&lt;/h3&gt;

&lt;p&gt;Now you have a personalized station picker:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7pg24q1bwwiihjzbz0q0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7pg24q1bwwiihjzbz0q0.png" alt="All the vocal stations" width="800" height="501"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;All the vocal stations&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I hope you enjoyed reading this as much as I enjoyed putting this together.&lt;/p&gt;

&lt;p&gt;Have a good one!&lt;/p&gt;

</description>
      <category>alfred</category>
      <category>digitallyimported</category>
      <category>workflow</category>
    </item>
    <item>
      <title>Using fzf to choose from a list of choices</title>
      <dc:creator>MoniqueLive</dc:creator>
      <pubDate>Wed, 06 Sep 2023 20:18:53 +0000</pubDate>
      <link>https://dev.to/moniquelive/using-fzf-to-choose-from-a-list-of-choices-5d4i</link>
      <guid>https://dev.to/moniquelive/using-fzf-to-choose-from-a-list-of-choices-5d4i</guid>
      <description>&lt;h2&gt;
  
  
  Some scenarios I use fzf to help me pick from a list of choices
&lt;/h2&gt;

&lt;h3&gt;
  
  
  #1 - picking which docker images I'd like to remove
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;fzfrmimage &lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="c"&gt;# - list all docker images, skipping the first line&lt;/span&gt;
  &lt;span class="c"&gt;# - feed these lines into fzf (user: TAB select/hit ENTER)&lt;/span&gt;
  &lt;span class="c"&gt;# - format a list of 'image:tag's and pass it to `docker image rm` &lt;/span&gt;
  &lt;span class="nv"&gt;images&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;docker image &lt;span class="nb"&gt;ls&lt;/span&gt; | &lt;span class="nb"&gt;tail&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; +2 | fzf | &lt;span class="nb"&gt;sed&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="s1"&gt;'s/\(\S*\) *\(\S*\).*/\1:\2/p'&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
  docker image &lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nv"&gt;$images&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  #2 - picking from pygments themes (styles)
&lt;/h3&gt;

&lt;p&gt;I used this as a oneliner (actually 2 for better legibility) in order to preview some sample code using the style.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pygmentize &lt;span class="nt"&gt;-L&lt;/span&gt; styles | &lt;span class="nb"&gt;sed&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="s1"&gt;'s/^* \(.*\):/\1/p'&lt;/span&gt; |&lt;span class="se"&gt;\&lt;/span&gt;
  fzf &lt;span class="nt"&gt;--preview&lt;/span&gt; &lt;span class="s2"&gt;"pygmentize -P style={} -l python ~/prj/python/bored/main.py"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;list all styles&lt;/li&gt;
&lt;li&gt;filter for lines that start with an asterisk&lt;/li&gt;
&lt;li&gt;remove the trailing ':' character&lt;/li&gt;
&lt;li&gt;feed the list into fzf with a sample code preview&lt;/li&gt;
&lt;li&gt;user: TAB select / hit ENTER&lt;/li&gt;
&lt;li&gt;fzf prints the selected themes&lt;/li&gt;
&lt;li&gt;profit!&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;FZF is a super flexible tool that I'm always looking for ways to leveraging its powers. Thanks &lt;a href="https://github.com/junegunn" rel="noopener noreferrer"&gt;Junegunn Choi&lt;/a&gt; for creating it!&lt;/p&gt;

</description>
      <category>fzf</category>
      <category>shell</category>
      <category>docker</category>
      <category>pygments</category>
    </item>
    <item>
      <title>Using nerd font symbols and emoji with any (unpatched) font in Linux</title>
      <dc:creator>MoniqueLive</dc:creator>
      <pubDate>Tue, 27 Jun 2023 23:29:05 +0000</pubDate>
      <link>https://dev.to/moniquelive/using-nerd-font-symbols-and-emoji-with-any-unpatched-font-in-linux-3kdo</link>
      <guid>https://dev.to/moniquelive/using-nerd-font-symbols-and-emoji-with-any-unpatched-font-in-linux-3kdo</guid>
      <description>&lt;p&gt;After I read &lt;a href="https://sw.kovidgoyal.net/kitty/faq/#kitty-is-not-able-to-use-my-favorite-font" rel="noopener noreferrer"&gt;the note on this question&lt;/a&gt; on the Kitty terminal FAQ I started paying attention to editors, ide's and terminals that support &lt;em&gt;fallback fonts&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;A fallback font is a reserve typeface containing symbols for as many Unicode characters as possible. When a display system encounters a character that is not part of the repertoire of any of the other available fonts, a symbol from a fallback font is used instead. Typically, a fallback font will contain symbols representative of the various types of Unicode characters.&lt;/em&gt; &lt;sup id="fnref1"&gt;1&lt;/sup&gt;&lt;/p&gt;

&lt;p&gt;But not all editors, ide's or terminals support them. Like the terminal emulator &lt;a href="https://github.com/alacritty/alacritty/issues/957" rel="noopener noreferrer"&gt;alacritty&lt;/a&gt; for example.&lt;/p&gt;

&lt;p&gt;But Linux's &lt;a href="https://www.fontconfig.org/" rel="noopener noreferrer"&gt;fontconfig&lt;/a&gt; package is very complete and it allows you to create font families, which I understood are virtual fonts you create in order to have the fallback mechanism manually set up.&lt;/p&gt;

&lt;p&gt;So let's cut to the chase! First create a file in &lt;code&gt;~/.config/fontconfig&lt;/code&gt; called &lt;code&gt;fonts.conf&lt;/code&gt; with the following contents:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?xml version="1.0"?&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;&amp;lt;!DOCTYPE fontconfig SYSTEM "urn:fontconfig:fonts.dtd"&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;fontconfig&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;match&lt;/span&gt; &lt;span class="na"&gt;target=&lt;/span&gt;&lt;span class="s"&gt;"font"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;edit&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"autohint"&lt;/span&gt; &lt;span class="na"&gt;mode=&lt;/span&gt;&lt;span class="s"&gt;"assign"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;bool&amp;gt;&lt;/span&gt;true&lt;span class="nt"&gt;&amp;lt;/bool&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/edit&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/match&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;alias&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;family&amp;gt;&lt;/span&gt;my-chosen-font-family&lt;span class="nt"&gt;&amp;lt;/family&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;prefer&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;family&amp;gt;&lt;/span&gt;JetBrains Mono&lt;span class="nt"&gt;&amp;lt;/family&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;family&amp;gt;&lt;/span&gt;Symbols Nerd Font&lt;span class="nt"&gt;&amp;lt;/family&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;family&amp;gt;&lt;/span&gt;Noto Color Emoji&lt;span class="nt"&gt;&amp;lt;/family&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/prefer&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/alias&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/fontconfig&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;&amp;lt;match&amp;gt;&lt;/code&gt; tag asks for &lt;a href="https://en.wikipedia.org/wiki/Font_hinting" rel="noopener noreferrer"&gt;auto-hinting&lt;/a&gt; in order to have better looking fonts.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;&amp;lt;alias&amp;gt;&lt;/code&gt; tag contains the name of your virtual font &lt;code&gt;my-chosen-font-family&lt;/code&gt; and the set of fonts that belong to it. In my case I have &lt;a href="https://www.jetbrains.com/lp/mono/" rel="noopener noreferrer"&gt;an unpatched (original) font&lt;/a&gt;, the &lt;a href="https://www.nerdfonts.com/font-downloads" rel="noopener noreferrer"&gt;symbols nerd font&lt;/a&gt; and the &lt;a href="https://github.com/googlefonts/noto-emoji" rel="noopener noreferrer"&gt;emoji one&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Now all you have to do is configure your apps to use it. In &lt;a href="https://alacritty.org/" rel="noopener noreferrer"&gt;alacritty&lt;/a&gt; it would be:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;font&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;normal&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;family&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;my-chosen-font-family&lt;/span&gt;
    &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Regular&lt;/span&gt;

  &lt;span class="na"&gt;bold&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;family&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;my-chosen-font-family&lt;/span&gt;
    &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Bold&lt;/span&gt;

  &lt;span class="na"&gt;italic&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;family&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;my-chosen-font-family&lt;/span&gt;
    &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Italic&lt;/span&gt;

  &lt;span class="na"&gt;bold_italic&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;family&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;my-chosen-font-family&lt;/span&gt;
    &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Bold Italic&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Enjoy!&lt;/p&gt;




&lt;ol&gt;

&lt;li id="fn1"&gt;
&lt;p&gt;&lt;a href="https://en.wikipedia.org/wiki/Fallback_font" rel="noopener noreferrer"&gt;https://en.wikipedia.org/wiki/Fallback_font&lt;/a&gt;&amp;nbsp;↩&lt;/p&gt;
&lt;/li&gt;

&lt;/ol&gt;

</description>
      <category>fontconfig</category>
      <category>nerdfont</category>
      <category>symbols</category>
      <category>fontfamily</category>
    </item>
    <item>
      <title>Passing multiple arguments to golang sub-templates</title>
      <dc:creator>MoniqueLive</dc:creator>
      <pubDate>Mon, 28 Nov 2022 21:04:31 +0000</pubDate>
      <link>https://dev.to/moniquelive/passing-multiple-arguments-to-golang-templates-16h8</link>
      <guid>https://dev.to/moniquelive/passing-multiple-arguments-to-golang-templates-16h8</guid>
      <description>&lt;p&gt;Have you ever wanted to pass multiple arguments to a go sub-template? If you google it you'll be convinced it's not possible. But bear with me.&lt;/p&gt;

&lt;p&gt;In go templates you can pass a single "argument" (pipeline in go parlance) to a "sub-template" defined block. But by creating a simple helper function you can pass as many arguments as you want. Simply add this function to your &lt;code&gt;FuncMap&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;els&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="n"&gt;any&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="n"&gt;any&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;els&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And you'll be able to create constructs such as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="n"&gt;template&lt;/span&gt; &lt;span class="s"&gt;"MyTemplate"&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arr&lt;/span&gt; &lt;span class="s"&gt;"first"&lt;/span&gt; &lt;span class="m"&gt;123&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Some&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;
&lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="n"&gt;template&lt;/span&gt; &lt;span class="s"&gt;"MyTemplate"&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arr&lt;/span&gt; &lt;span class="s"&gt;"second"&lt;/span&gt; &lt;span class="m"&gt;456&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Other&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;

&lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="n"&gt;define&lt;/span&gt; &lt;span class="s"&gt;"MyTeplate"&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;
  &lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="n"&gt;strArg&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;
  &lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="n"&gt;intArg&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;
  &lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="n"&gt;valArg&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;

  &lt;span class="n"&gt;This&lt;/span&gt; &lt;span class="n"&gt;is&lt;/span&gt; &lt;span class="n"&gt;my&lt;/span&gt; &lt;span class="n"&gt;str&lt;/span&gt; &lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="n"&gt;strArg&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt; &lt;span class="n"&gt;parameter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;
  &lt;span class="o"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="n"&gt;end&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I named &lt;code&gt;arr&lt;/code&gt; my helper func, but you can call it whatever you want.&lt;/p&gt;

&lt;p&gt;Enjoy!&lt;/p&gt;

</description>
      <category>go</category>
      <category>template</category>
      <category>arguments</category>
    </item>
    <item>
      <title>Auto activate and deactivate python venv using zsh (and fish)</title>
      <dc:creator>MoniqueLive</dc:creator>
      <pubDate>Fri, 17 Dec 2021 15:01:10 +0000</pubDate>
      <link>https://dev.to/moniquelive/auto-activate-and-deactivate-python-venv-using-zsh-4dlm</link>
      <guid>https://dev.to/moniquelive/auto-activate-and-deactivate-python-venv-using-zsh-4dlm</guid>
      <description>&lt;p&gt;When I found out about python venv (&lt;code&gt;apt-get install python3-venv&lt;/code&gt;) I became an instant addict. It's clean, it's built-in and it's explicit.&lt;/p&gt;

&lt;p&gt;Now every time I create a new project folder I automatically run &lt;code&gt;python3 -mvenv venv &amp;amp;&amp;amp; source ./venv/bin/activate&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;But typing &lt;code&gt;./venv/bin/activate&lt;/code&gt; and then &lt;code&gt;deactivate&lt;/code&gt; is too much work for my lazy programmer head.&lt;/p&gt;

&lt;p&gt;So I decided to finally invest 10 minutes to free me from activating and deactivating python's env every time I enter or leave a folder with my standard &lt;code&gt;./venv&lt;/code&gt; folder:&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;#---------------------------------------------- chpwd pyvenv ---&lt;/span&gt;
python_venv&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="nv"&gt;MYVENV&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;./venv
  &lt;span class="c"&gt;# when you cd into a folder that contains $MYVENV&lt;/span&gt;
  &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="nv"&gt;$MYVENV&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;source&lt;/span&gt; &lt;span class="nv"&gt;$MYVENV&lt;/span&gt;/bin/activate &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; /dev/null 2&amp;gt;&amp;amp;1
  &lt;span class="c"&gt;# when you cd into a folder that doesn't&lt;/span&gt;
  &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="nv"&gt;$MYVENV&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; deactivate &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; /dev/null 2&amp;gt;&amp;amp;1
&lt;span class="o"&gt;}&lt;/span&gt;
autoload &lt;span class="nt"&gt;-U&lt;/span&gt; add-zsh-hook
add-zsh-hook chpwd python_venv

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

&lt;/div&gt;



&lt;p&gt;edit: just figured out that deactivating was working because of other stuff installed in my shell. Now it's a bit more agressive but works 100%&lt;/p&gt;

&lt;p&gt;edit2: been trying out fish shell. Here it is translated to fish script:&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;function &lt;/span&gt;python_venv &lt;span class="nt"&gt;--on-variable&lt;/span&gt; PWD
    &lt;span class="nb"&gt;set &lt;/span&gt;myvenv ./venv
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="nb"&gt;test&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="nv"&gt;$myvenv&lt;/span&gt;
        &lt;span class="nb"&gt;source&lt;/span&gt; &lt;span class="nv"&gt;$myvenv&lt;/span&gt;/bin/activate.fish
    &lt;span class="k"&gt;else if &lt;/span&gt;&lt;span class="nb"&gt;type&lt;/span&gt; &lt;span class="nt"&gt;-q&lt;/span&gt; deactivate
        deactivate
    end
end
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>zsh</category>
      <category>python</category>
      <category>venv</category>
      <category>fish</category>
    </item>
    <item>
      <title>Python3 + GTK+3 + Glade + Templates = &lt;3</title>
      <dc:creator>MoniqueLive</dc:creator>
      <pubDate>Sun, 28 Mar 2021 01:26:28 +0000</pubDate>
      <link>https://dev.to/moniquelive/python3-gtk-3-glade-templates-3-1n9j</link>
      <guid>https://dev.to/moniquelive/python3-gtk-3-glade-templates-3-1n9j</guid>
      <description>&lt;p&gt;Many software that you use on your Gnome environment could've been developed with Python. Apps like Gnome Music and Gnome Tweaks are some examples.&lt;/p&gt;

&lt;p&gt;In this article I'll show you a minimal example in order to give you a foundation for your ideas. Let's go:&lt;/p&gt;

&lt;h2&gt;
  
  
  Create a basic layout on Glade:
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsuzcky8ibzokyhfcqv2q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsuzcky8ibzokyhfcqv2q.png" alt="GtkApplicationWindow" width="800" height="550"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Stuff you need to pay attention to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The top level component is a &lt;strong&gt;GtkApplicationWindow&lt;/strong&gt; (you can find it under &lt;em&gt;Toplevels&lt;/em&gt; button)&lt;/li&gt;
&lt;li&gt;While it's selected, check the &lt;em&gt;Composite&lt;/em&gt; checkbox on the farther right (&lt;strong&gt;super important!&lt;/strong&gt;)&lt;/li&gt;
&lt;li&gt;When you check the &lt;em&gt;Composite&lt;/em&gt; checkbox the &lt;em&gt;ID&lt;/em&gt; field becomes &lt;em&gt;Class Name&lt;/em&gt;. Give it a name and save it, we'll use it soon&lt;/li&gt;
&lt;li&gt;Give the button an &lt;em&gt;ID&lt;/em&gt; and save it, we'll use it soon&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With the Button selected, switch to the &lt;em&gt;Signals&lt;/em&gt; tab:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2p580mbgbc817xaaufe7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2p580mbgbc817xaaufe7.png" alt="Button Signals" width="800" height="484"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Click on the &lt;em&gt;Handler&lt;/em&gt; column on the &lt;em&gt;clicked&lt;/em&gt; Signal row&lt;/li&gt;
&lt;li&gt;Type the first letter of your button's name&lt;/li&gt;
&lt;li&gt;Accept the suggestion (&lt;em&gt;btnMain_clicked_cb&lt;/em&gt;, in my example) and save it, we'll use it soon&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And that's it for Glade. Save your &lt;em&gt;.glade&lt;/em&gt; file on your project dir.&lt;/p&gt;

&lt;h2&gt;
  
  
  Create a basic Python skeleton:
&lt;/h2&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="n"&gt;gi&lt;/span&gt;
&lt;span class="n"&gt;gi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;require_version&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Gtk&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;3.0&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;gi.repository&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;GLib&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Gio&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Gtk&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;


&lt;span class="c1"&gt;#
# 1. our .glade file (may contain paths)
#
&lt;/span&gt;&lt;span class="nd"&gt;@Gtk.Template.from_file&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;a.glade&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AppWindow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Gtk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ApplicationWindow&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="c1"&gt;#
&lt;/span&gt;    &lt;span class="c1"&gt;# 2. the GtkApplicationWindow class
&lt;/span&gt;    &lt;span class="c1"&gt;#
&lt;/span&gt;    &lt;span class="n"&gt;__gtype_name__&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;app_window&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

    &lt;span class="c1"&gt;#
&lt;/span&gt;    &lt;span class="c1"&gt;# 3. the Button name we saved above
&lt;/span&gt;    &lt;span class="c1"&gt;#
&lt;/span&gt;    &lt;span class="n"&gt;btnMain&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Gtk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Button&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Gtk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Template&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Child&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="c1"&gt;#
&lt;/span&gt;    &lt;span class="c1"&gt;# 4. the signal handler name we saved above
&lt;/span&gt;    &lt;span class="c1"&gt;#
&lt;/span&gt;    &lt;span class="nd"&gt;@Gtk.Template.Callback&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;btnMain_clicked_cb&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;widget&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;_kwargs&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;btnMain&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;widget&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;widget&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_label&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;


&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Application&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Gtk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Application&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;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="nf"&gt;super&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;application_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;dev.monique.Gtk1&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                         &lt;span class="n"&gt;flags&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;Gio&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ApplicationFlags&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FLAGS_NONE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;window&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;do_activate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;window&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;window&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="nc"&gt;AppWindow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;application&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;present&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;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;__main__&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nc"&gt;Application&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You'll also need to:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;It may complain about missing libraries, just read the error output and install the missing dependencies (I had to &lt;code&gt;apt install libcairo2-dev libgirepository1.0-dev&lt;/code&gt;)&lt;/p&gt;

&lt;p&gt;With this code you'll be able to get started.&lt;/p&gt;

&lt;p&gt;Good luck!&lt;/p&gt;

</description>
      <category>python</category>
      <category>gtk</category>
      <category>glade</category>
    </item>
    <item>
      <title>How I compile OpenCV on Linux with lots of bells and whistles (CuDNN, CUDA, OpenGL, Qt, TrueType, Video CODECs)</title>
      <dc:creator>MoniqueLive</dc:creator>
      <pubDate>Tue, 16 Feb 2021 02:09:32 +0000</pubDate>
      <link>https://dev.to/moniquelive/how-i-compile-opencv-on-linux-with-lots-of-bells-and-whistles-cudnn-cuda-opengl-qt-truetype-video-codecs-3hmo</link>
      <guid>https://dev.to/moniquelive/how-i-compile-opencv-on-linux-with-lots-of-bells-and-whistles-cudnn-cuda-opengl-qt-truetype-video-codecs-3hmo</guid>
      <description>&lt;p&gt;Em &lt;a href="https://monique.dev/posts/opencv/" rel="noopener noreferrer"&gt;português&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;OpenCV is a beast of a library. It's huge. But it's also super flexible. You typically choose what your binary will contain by providing optional dependencies but sometimes you have to nudge it to the direction you need.&lt;/p&gt;

&lt;p&gt;In this guide I'll show you how I compile it with the longest cmake line you'll ever see (hopefully) and I'll also add comments so you know what you need to compile it successfully.&lt;/p&gt;

&lt;p&gt;Let's get started.&lt;/p&gt;

&lt;h1&gt;
  
  
  Downloading
&lt;/h1&gt;

&lt;p&gt;You need two projects in order to build OpenCV: the &lt;a href="https://github.com/opencv/opencv" rel="noopener noreferrer"&gt;OpenCV&lt;/a&gt; source code and OpenCV &lt;a href="https://github.com/opencv/opencv_contrib" rel="noopener noreferrer"&gt;contrib&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;You can either download the latest versions as as zip/tar ball or you can clone them and checkout the version (aka tag) you need.&lt;/p&gt;

&lt;p&gt;Whatever way you choose, for the purpose of this tutorial all you need is both projects to be sitting next to each other on the same folder:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9j200ku8p9m40i4yci2p.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9j200ku8p9m40i4yci2p.png" alt="Alt Text" width="388" height="228"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Dependencies
&lt;/h1&gt;

&lt;p&gt;If you install all the depencies I explain bellow you'll have:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;--   OpenCV modules:
--     To be built:                 aruco bgsegm bioinspired calib3d ccalib core cudaarithm cudabgsegm cudacodec cudafeatures2d cudafilters cudaimgproc cudalegacy cudaobjdetect cudaoptflow cudastereo cudawarping cudev cvv datasets dnn dnn_objdetect dnn_superres dpm face features2d flann freetype fuzzy gapi hfs highgui img_hash imgcodecs imgproc intensity_transform line_descriptor mcc ml objdetect optflow phase_unwrapping photo plot python3 quality rapid reg rgbd saliency shape stereo stitching structured_light superres surface_matching text tracking video videoio videostab xfeatures2d ximgproc xobjdetect xphoto
--     Disabled:                    world
--     Disabled by dependency:      -
--     Unavailable:                 alphamat cnn_3dobj hdf java julia matlab ovis python2 sfm ts viz
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is what you'll need:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;python3 + numpy&lt;/code&gt; - I generally install it globally, outside of any venv/virtualenv sandboxes. Having OpenCV installed globally I can reference it on the venv sandboxes when needed. You'll see a similar cmake output:
&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmkf4fj56cwg7joh5c0pj.png" alt="Alt Text" width="798" height="93"&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;python3-pyqt5.qtopengl&lt;/code&gt; - it's enough to bring in the dependencies in order to detect Qt + OpenGL. Why is OpenGL so important, you may ask? Hardware accelerated frame rates. You'll see a similar cmake output:
&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fri1jx1v2xq8c6aahwfw3.png" alt="Alt Text" width="797" height="103"&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ffmpeg + gstreamer&lt;/code&gt; - if you want to load different video encodings:
&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkv61j50z5xf9yp5zbuyy.png" alt="Alt Text" width="800" height="330"&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;libfreetype-dev + libharfbuzz-dev&lt;/code&gt; - if you want support for truetype fonts&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;CUDA + CuDNN&lt;/code&gt; - this one deserves a more detailed explanation bellow.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  CUDA + CuDNN
&lt;/h2&gt;

&lt;p&gt;CUDA (and CuDNN) are usually installed under the same directory. And this directory is typically &lt;code&gt;/usr/local/cuda-&amp;lt;version&amp;gt;&lt;/code&gt;. But this is not a rule. I use PopOS and it gets installed in &lt;code&gt;/usr/lib/cuda-&amp;lt;version&amp;gt;&lt;/code&gt;. It can also have as many versions as you want installed in parallel:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F61phl56afoj4ziabwrry.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F61phl56afoj4ziabwrry.png" alt="image" width="520" height="248"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you can see above, even though CUDA-11.2 was installed automatically (it's the current version as of today), CuDNN is only available up until 11.1 so I was forced to install CUDA-11.1 as well in order to have both CUDA and CuDNN installed on the same tree structure.&lt;/p&gt;

&lt;p&gt;In order for cmake to find CUDA and CuDNN all you need is add &lt;code&gt;&amp;lt;your CUDA root&amp;gt;/bin&lt;/code&gt; to your path. &lt;/p&gt;

&lt;p&gt;You can check like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftdsyvs01m2wx9ad387an.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftdsyvs01m2wx9ad387an.png" alt="Alt Text" width="800" height="262"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Super easy right? 🤣&lt;/p&gt;

&lt;p&gt;Let's build it then!&lt;/p&gt;

&lt;h1&gt;
  
  
  Check for dependencies
&lt;/h1&gt;

&lt;p&gt;In order to compile you need to create a &lt;code&gt;build&lt;/code&gt; folder inside your opencv library root folder (&lt;code&gt;cd opencv; mkdir build; cd build&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;Now take a deep breath and enjoy the largest command line I've ever written for a single command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;cmake &lt;span class="nt"&gt;-D&lt;/span&gt; &lt;span class="nv"&gt;CMAKE_CXX_COMPILER&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/usr/bin/g++ &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;-D&lt;/span&gt; CUDA_HOST_COMPILER:FILEPATH&lt;span class="o"&gt;=&lt;/span&gt;/usr/bin/gcc-9 &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;-D&lt;/span&gt; &lt;span class="nv"&gt;CUDA_NVCC_FLAGS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nt"&gt;--expt-relaxed-constexpr&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;-D&lt;/span&gt; &lt;span class="nv"&gt;WITH_CUDA&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;ON &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;-D&lt;/span&gt; &lt;span class="nv"&gt;WITH_CUDNN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;ON &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;-D&lt;/span&gt; &lt;span class="nv"&gt;CUDNN_INCLUDE_DIR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/usr/lib/cuda-11.1/include &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;-D&lt;/span&gt; &lt;span class="nv"&gt;OPENCV_DNN_CUDA&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;ON &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;-D&lt;/span&gt; &lt;span class="nv"&gt;ENABLE_FAST_MATH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1 &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;-D&lt;/span&gt; &lt;span class="nv"&gt;CUDA_FAST_MATH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1 &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;-D&lt;/span&gt; &lt;span class="nv"&gt;CUDA_ARCH_BIN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;8.6 &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;-D&lt;/span&gt; &lt;span class="nv"&gt;WITH_CUBLAS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1 &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;-D&lt;/span&gt; &lt;span class="nv"&gt;WITH_TBB&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;ON &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;-D&lt;/span&gt; &lt;span class="nv"&gt;WITH_OPENMP&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;ON &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;-D&lt;/span&gt; &lt;span class="nv"&gt;WITH_IPP&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;ON &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;-D&lt;/span&gt; &lt;span class="nv"&gt;CMAKE_BUILD_TYPE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;RELEASE &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;-D&lt;/span&gt; &lt;span class="nv"&gt;WITH_CSTRIPES&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;ON &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;-D&lt;/span&gt; &lt;span class="nv"&gt;OPENCV_EXTRA_MODULES_PATH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;../../opencv_contrib/modules &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;-D&lt;/span&gt; &lt;span class="nv"&gt;CMAKE_INSTALL_PREFIX&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/usr/local/ &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;-D&lt;/span&gt; &lt;span class="nv"&gt;WITH_QT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;ON &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;-D&lt;/span&gt; &lt;span class="nv"&gt;WITH_OPENGL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;ON &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;-D&lt;/span&gt; &lt;span class="nv"&gt;BUILD_EXAMPLES&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;OFF &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;-D&lt;/span&gt; &lt;span class="nv"&gt;BUILD_DOCS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;OFF &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;-D&lt;/span&gt; &lt;span class="nv"&gt;BUILD_PERF_TESTS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;OFF &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;-D&lt;/span&gt; &lt;span class="nv"&gt;BUILD_TESTS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;OFF &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;-D&lt;/span&gt; &lt;span class="nv"&gt;BUILD_opencv_python3&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;ON &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;-D&lt;/span&gt; &lt;span class="nv"&gt;PYTHON3_EXECUTABLE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;which python3&lt;span class="si"&gt;)&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;-D&lt;/span&gt; &lt;span class="nv"&gt;PYTHON_INCLUDE_DIR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;python2 &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s2"&gt;"from distutils.sysconfig import get_python_inc; print(get_python_inc())"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;-D&lt;/span&gt; &lt;span class="nv"&gt;PYTHON3_INCLUDE_DIR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;python3 &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s2"&gt;"from distutils.sysconfig import get_python_inc; print(get_python_inc())"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;-D&lt;/span&gt; &lt;span class="nv"&gt;PYTHON3_LIBRARY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;python3 &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s2"&gt;"from distutils.sysconfig import get_config_var;from os.path import dirname,join ; print(join(dirname(get_config_var('LIBPC')),get_config_var('LDLIBRARY')))"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;-D&lt;/span&gt; &lt;span class="nv"&gt;PYTHON3_NUMPY_INCLUDE_DIRS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;python3 &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s2"&gt;"import numpy; print(numpy.get_include())"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;-D&lt;/span&gt; &lt;span class="nv"&gt;PYTHON3_PACKAGES_PATH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;python3 &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s2"&gt;"from distutils.sysconfig import get_python_lib; print(get_python_lib())"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
..
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Don't miss the double dots at the end!&lt;/p&gt;

&lt;p&gt;Some configurations worth explaining:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;CMAKE_CXX_COMPILER&lt;/code&gt; - to compile c++ files&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;CUDA_HOST_COMPILER:FILEPATH&lt;/code&gt; - to compile cuda files - During &lt;code&gt;system76-cudnn&lt;/code&gt; package installation I noticed it installed gcc-9. Very deterministic (not), I know.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;CUDA_NVCC_FLAGS&lt;/code&gt; - needed some day, may remove eventually&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;CUDNN_INCLUDE_DIR&lt;/code&gt; - check your cuda home folder&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;CUDA_ARCH_BIN&lt;/code&gt; - the architecture of your GPU. Check it here &lt;a href="https://developer.nvidia.com/cuda-gpus" rel="noopener noreferrer"&gt;https://developer.nvidia.com/cuda-gpus&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;OPENCV_EXTRA_MODULES_PATH&lt;/code&gt; - relative or absolute path to opencv_contrib folder&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In order to validate if all your dependencies are ok, read the line &lt;code&gt;Unavailable: ...&lt;/code&gt; in the beginning of the previous section and check for differences with yours.&lt;/p&gt;

&lt;p&gt;If you need to rerun cmake, leave the &lt;code&gt;build&lt;/code&gt; folder, destroy it, recreate it, change back to it, only then rerun cmake... It's a tedious process but there's no shortcut here unfortunately.&lt;/p&gt;

&lt;h1&gt;
  
  
  Compiling
&lt;/h1&gt;

&lt;p&gt;This step is the easiest. Given all the dependencies are met all you have to do is run the make command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;make &lt;span class="nt"&gt;-j&lt;/span&gt;&amp;lt;number of processes&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I highly recommend using the -j flag in order to cut compilation time. If you want to keep using your machine while the compilation is running, I recommend using &lt;code&gt;$(nproc)-2&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;For your reference, using &lt;code&gt;-j60&lt;/code&gt; + nvme, the compilation process takes 5m30s here.&lt;/p&gt;

&lt;p&gt;If anything goes wrong don't be afraid to scroll up (or search for &lt;code&gt;error:&lt;/code&gt;) and check what happened.&lt;/p&gt;

&lt;h1&gt;
  
  
  Installing
&lt;/h1&gt;

&lt;p&gt;If everything went fine and dandy:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8dmme6y95n7525ca9qf8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8dmme6y95n7525ca9qf8.png" alt="Alt Text" width="800" height="91"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;💯% baby!&lt;/p&gt;

&lt;p&gt;All you need to do is:&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;make &lt;span class="nb"&gt;install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's the only time you need to invoke root's super powers in order to write files on &lt;code&gt;/usr/local&lt;/code&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  Validating
&lt;/h1&gt;

&lt;p&gt;To test your achievement:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;python3
&lt;span class="gp"&gt;&amp;gt;&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; import cv2
&lt;span class="gp"&gt;&amp;gt;&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; print&lt;span class="o"&gt;(&lt;/span&gt;cv2.getBuildInformation&lt;span class="o"&gt;())&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should see the same output as cmake's.&lt;/p&gt;

&lt;h1&gt;
  
  
  Using
&lt;/h1&gt;

&lt;p&gt;In order to use OpenCV with a venv (you can read more about venv &lt;a href="https://dev.to/moniquelive/autocompletion-globally-installed-opencv-with-pycharm-308a"&gt;here&lt;/a&gt;) use the flags:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python &lt;span class="nt"&gt;-mvenv&lt;/span&gt; &lt;span class="nt"&gt;--system-site-packages&lt;/span&gt; venv 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will create a sub-folder named &lt;code&gt;venv&lt;/code&gt; with a sandbox that comes with "system wide packages", such as ... you know it.&lt;/p&gt;

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

&lt;p&gt;If you read until here, congrats, you are a very determined person 🤣&lt;/p&gt;

&lt;p&gt;If you need any help just leave a comment!&lt;/p&gt;

&lt;p&gt;Good luck.&lt;/p&gt;

</description>
      <category>opencv</category>
      <category>python</category>
      <category>cuda</category>
    </item>
    <item>
      <title>Pre-compiled pytorch versions</title>
      <dc:creator>MoniqueLive</dc:creator>
      <pubDate>Wed, 20 Jan 2021 17:51:25 +0000</pubDate>
      <link>https://dev.to/moniquelive/pre-compiled-pytorch-versions-5b7l</link>
      <guid>https://dev.to/moniquelive/pre-compiled-pytorch-versions-5b7l</guid>
      <description>&lt;p&gt;I had just found about a repository that just saved my bacon so I decided to share it with you guys.&lt;/p&gt;

&lt;p&gt;If you go to pytorch's website, you'll be given a lot of choices to install it:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Foixb0x4hndw3ddm10gub.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Foixb0x4hndw3ddm10gub.png" alt="Alt Text" width="800" height="306"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The thing is, if you want to install a different version than the one listed (1.7.1 as of today) you'll begin a not very pleasant treasure hunt.&lt;/p&gt;

&lt;p&gt;There's a repo that somehow took me quite a while to find here:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;https://download.pytorch.org/whl/torch_stable.html
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But you don't need to click on it! You can ask &lt;code&gt;pip&lt;/code&gt; to fetch it for you:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;pip[3] install pytorch==1.6.0+cu101 -f https://download.pytorch.org/whl/torch_stable.html
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And voilá, your package will be installed automagically!&lt;/p&gt;

&lt;p&gt;Now some extra tips:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Some &lt;code&gt;cuda&lt;/code&gt; versions are considered "default". For instance if you look for &lt;code&gt;1.6.0+cu102&lt;/code&gt; you won't find it, that's because installing &lt;code&gt;pip install cuda==1.6.0&lt;/code&gt; will automatically fetch cuda's &lt;code&gt;10.2&lt;/code&gt; version.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If you're a masochist and need the CPU-only version: &lt;code&gt;pip install 1.6.0+cpu&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;To save this repo on your &lt;code&gt;requirements.txt&lt;/code&gt;, just add this as the first line of it:&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;-f https://download.pytorch.org/whl/torch_stable.html

&lt;/span&gt;&lt;span class="c"&gt;...
&lt;/span&gt;&lt;span class="go"&gt;torch==1.6.0+cu110
&lt;/span&gt;&lt;span class="c"&gt;...
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Happy torching!&lt;/p&gt;

</description>
      <category>python</category>
      <category>pytorch</category>
      <category>cuda</category>
      <category>gpu</category>
    </item>
    <item>
      <title>Autocompletion globally installed OpenCV with PyCharm</title>
      <dc:creator>MoniqueLive</dc:creator>
      <pubDate>Mon, 28 Dec 2020 17:19:43 +0000</pubDate>
      <link>https://dev.to/moniquelive/autocompletion-globally-installed-opencv-with-pycharm-308a</link>
      <guid>https://dev.to/moniquelive/autocompletion-globally-installed-opencv-with-pycharm-308a</guid>
      <description>&lt;h2&gt;
  
  
  Intro
&lt;/h2&gt;

&lt;p&gt;For a long time I was a user of the &lt;a href="https://virtualenv.pypa.io/en/latest/" rel="noopener noreferrer"&gt;virtualenv&lt;/a&gt; module. But ever since I learned about the standard module &lt;a href="https://docs.python.org/3/tutorial/venv.html" rel="noopener noreferrer"&gt;venv&lt;/a&gt; I became a devotee.&lt;/p&gt;

&lt;p&gt;For starters it comes bundled with python (or by installing the &lt;code&gt;python3-venv&lt;/code&gt; package). It's also more predictable than virtualenv since you don't need to mess with your &lt;code&gt;.{bash/zsh/fish}rc&lt;/code&gt; files and it's generally installed under your project's root dir.&lt;/p&gt;

&lt;p&gt;But there's one exception for using locally installed packages, and it's packages that need to be built on your machine. OpenCV is one of them. You can install a pre-built one using &lt;code&gt;pip install opencv-python-contrib&lt;/code&gt; but it won't take advantage of your shiny new GPU.&lt;/p&gt;

&lt;h2&gt;
  
  
  OpenCV
&lt;/h2&gt;

&lt;p&gt;Building OpenCV is a whole topic on itself but assuming you did all the steps (&lt;code&gt;cmake + infinite flags / sudo make install&lt;/code&gt;) it'll be installed on your machine globally (on &lt;code&gt;/usr/lib&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;To use it locally on a &lt;code&gt;venv&lt;/code&gt; isolated environment, you have to use the following flag:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python &lt;span class="nt"&gt;-mvenv&lt;/span&gt; &lt;span class="nt"&gt;--system-site-packages&lt;/span&gt; venv 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;--system-site-packages&lt;/code&gt; flag creates a local environment but includes all the globally installed modules.&lt;/p&gt;

&lt;p&gt;Just for completion sake, don't forget to active the environment:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;source &lt;/span&gt;venv/bin/activate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  PyCharm
&lt;/h2&gt;

&lt;p&gt;Now if you use PyCharm and would love to see the autocompletion work with your just installed OpenCV there's one extra step.&lt;/p&gt;

&lt;p&gt;First of all, tell PyCharm to use your venv by going to &lt;code&gt;Settings -&amp;gt; Python Interpreter -&amp;gt; "cog" button -&amp;gt; Add -&amp;gt; Existing environment&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;(If you create your venv first and then open the directory on PyCharm, it'll autodetect it)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;But by default PyCharm won't find the &lt;code&gt;.so&lt;/code&gt; built for OpenCV. You have to tell it where it is.&lt;/p&gt;

&lt;p&gt;To find where yours was installed you can use the &lt;code&gt;find&lt;/code&gt; tool:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;find /usr &lt;span class="nt"&gt;-name&lt;/span&gt; cv2&lt;span class="se"&gt;\*&lt;/span&gt;so
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Mine was found under &lt;code&gt;/usr/lib/python3/dist-packages/cv2/python-3.8/cv2.cpython-38-x86_64-linux-gnu.so&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Now you get back to the interpreter settings (&lt;code&gt;Settings -&amp;gt; Python Interpreter -&amp;gt; "cog" button -&amp;gt; Show all&lt;/code&gt;), select the interpreter for your project, click on the toolbar's last button (&lt;code&gt;Show paths for the selected interpreter&lt;/code&gt;) and add the above directory removing your &lt;code&gt;*.so&lt;/code&gt; file name:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Frkajktmxuejw9ur1hx0e.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Frkajktmxuejw9ur1hx0e.png" alt="Show paths for the selected interpreter" width="644" height="509"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After this last extra step autocomplete should work like a charm (oops...).&lt;/p&gt;

&lt;p&gt;Happy coding!&lt;/p&gt;

</description>
      <category>python</category>
      <category>opencv</category>
      <category>pycharm</category>
    </item>
  </channel>
</rss>
