<?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.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F74371%2Fc95e8dd1-b623-49a2-bc11-d621a3a3147f.jpeg</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>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"&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://res.cloudinary.com/practicaldev/image/fetch/s--h3UDinmU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4h6d9yvzfkbk3losdov9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--h3UDinmU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4h6d9yvzfkbk3losdov9.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://res.cloudinary.com/practicaldev/image/fetch/s--S-iKY2UH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nb20ohcdidm57m9b5xzu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--S-iKY2UH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nb20ohcdidm57m9b5xzu.png" alt="double clicking on List Filter" width="800" 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"&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"&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://res.cloudinary.com/practicaldev/image/fetch/s--FhkKjuLv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mf69tbqw5z6ryuzqfnqf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--FhkKjuLv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mf69tbqw5z6ryuzqfnqf.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://res.cloudinary.com/practicaldev/image/fetch/s--jWGM_vG7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7pg24q1bwwiihjzbz0q0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--jWGM_vG7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7pg24q1bwwiihjzbz0q0.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"&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"&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"&gt;alacritty&lt;/a&gt; for example.&lt;/p&gt;

&lt;p&gt;But Linux's &lt;a href="https://www.fontconfig.org/"&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"&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/"&gt;an unpatched (original) font&lt;/a&gt;, the &lt;a href="https://www.nerdfonts.com/font-downloads"&gt;symbols nerd font&lt;/a&gt; and the &lt;a href="https://github.com/googlefonts/noto-emoji"&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/"&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"&gt;https://en.wikipedia.org/wiki/Fallback_font&lt;/a&gt; ↩&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://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsuzcky8ibzokyhfcqv2q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsuzcky8ibzokyhfcqv2q.png" alt="GtkApplicationWindow"&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://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2p580mbgbc817xaaufe7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2p580mbgbc817xaaufe7.png" alt="Button Signals"&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;/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="800" 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="800" 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="329"&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="90"&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://res.cloudinary.com/practicaldev/image/fetch/s--in9VapAT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/oixb0x4hndw3ddm10gub.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--in9VapAT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/oixb0x4hndw3ddm10gub.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/"&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"&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://res.cloudinary.com/practicaldev/image/fetch/s--UiyQRH83--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/rkajktmxuejw9ur1hx0e.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--UiyQRH83--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/rkajktmxuejw9ur1hx0e.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>
    <item>
      <title>OBS Studio as a Virtual Webcam</title>
      <dc:creator>MoniqueLive</dc:creator>
      <pubDate>Tue, 22 Dec 2020 17:18:35 +0000</pubDate>
      <link>https://dev.to/moniquelive/obs-studio-as-a-virtual-webcam-281d</link>
      <guid>https://dev.to/moniquelive/obs-studio-as-a-virtual-webcam-281d</guid>
      <description>&lt;p&gt;In the year 2020 video conferencing exploded worldwide. It became a necessity for many (now) remote workers.&lt;/p&gt;

&lt;p&gt;If you happen to be a lucky (debian-based) Linux user, this set of steps will show you how to use OBS Studio as a video source in any conferencing software (Google Meet, Zoom.us, Discord, etc.). Here we go:&lt;/p&gt;

&lt;h2&gt;
  
  
  Install OBS, libOBS, v4l loopback, qt-dev
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt-get &lt;span class="nb"&gt;install &lt;/span&gt;obs-studio libobs-dev v4l2loopback-dkms qtbase5-dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Configure the kernel module (v4l2loopback)
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo touch&lt;/span&gt; /etc/modules-load.d/v4l2loopback.conf
&lt;span class="nb"&gt;sudo echo &lt;/span&gt;v4l2loopback &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; /etc/modules-load.d/v4l2loopback.conf
&lt;span class="nb"&gt;sudo echo&lt;/span&gt; &lt;span class="s1"&gt;'options v4l2loopback card_label="OBS Video Source" video_nr=10 exclusive_caps=1'&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; /etc/modprobe.d/v4l2-obs-studio.conf
&lt;span class="nb"&gt;sudo &lt;/span&gt;depmod &lt;span class="nt"&gt;-a&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;modprobe v4l2loopback
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Parameters:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;video_nr&lt;/code&gt; device number that will be created &lt;code&gt;/dev/video10&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;card_label&lt;/code&gt; camera name that will show up on Meet/Zoom/Discord/etc&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;exclusive_caps&lt;/code&gt; to work with Google Chrome&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Install the OBS plugin (v4l2sink)
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone &lt;span class="nt"&gt;--recursive&lt;/span&gt; https://github.com/obsproject/obs-studio.git &lt;span class="c"&gt;# OBS&lt;/span&gt;
git clone git@github.com:CatxFish/obs-v4l2sink.git &lt;span class="c"&gt;# Plugin&lt;/span&gt;

&lt;span class="nb"&gt;cd &lt;/span&gt;obs-v4l2sink
&lt;span class="nb"&gt;mkdir &lt;/span&gt;build &lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nb"&gt;cd &lt;/span&gt;build
cmake &lt;span class="nt"&gt;-DLIBOBS_INCLUDE_DIR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"../../obs-studio/libobs"&lt;/span&gt; &lt;span class="nt"&gt;-DCMAKE_INSTALL_PREFIX&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/usr ..
make &lt;span class="nt"&gt;-j&lt;/span&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;&lt;em&gt;(edit: I just found out how to install plugins on your home dir instead of messing around your system's filesystem)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;It'll be installed in &lt;code&gt;/usr/lib/obs-plugins&lt;/code&gt;, but let's install it on our home directory:&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;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; ~/.config/obs-studio/plugins/v4l2sink/&lt;span class="o"&gt;{&lt;/span&gt;data,bin/64bit&lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="nb"&gt;ln&lt;/span&gt; &lt;span class="nt"&gt;-sf&lt;/span&gt; /usr/lib/obs-plugins/v4l2sink.so ~/.config/obs-studio/plugins/v4l2sink/bin/64bit/
&lt;span class="nb"&gt;ln&lt;/span&gt; &lt;span class="nt"&gt;-sf&lt;/span&gt; /usr/share/obs-plugins/v4l2sink/locale ~/.config/obs-studio/plugins/v4l2sink/data/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If all worked, on the &lt;code&gt;Tools&lt;/code&gt; menu there'll be an item &lt;code&gt;V4L2 Video Output&lt;/code&gt;.&lt;br&gt;
Set the device to &lt;code&gt;/dev/video10&lt;/code&gt;, the video format to &lt;code&gt;YUY2&lt;/code&gt;. Click on &lt;code&gt;Auto-Start&lt;/code&gt;, &lt;code&gt;Start&lt;/code&gt; and create a scene...&lt;/p&gt;

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

</description>
    </item>
    <item>
      <title>Haskell LSP (bonus: for Vim)</title>
      <dc:creator>MoniqueLive</dc:creator>
      <pubDate>Tue, 27 Oct 2020 01:04:56 +0000</pubDate>
      <link>https://dev.to/moniquelive/haskell-lsp-bonus-for-vim-4nlj</link>
      <guid>https://dev.to/moniquelive/haskell-lsp-bonus-for-vim-4nlj</guid>
      <description>&lt;p&gt;So you enjoy coding in Haskell. And you heard kids nowadays code using this &lt;a href="https://microsoft.github.io/language-server-protocol/" rel="noopener noreferrer"&gt;LSP&lt;/a&gt; thingy.&lt;/p&gt;

&lt;p&gt;Let's cut to the chase: LSP is a spec that standardizes auto-completion, code navigation, linting, and all good stuff usually found in modern IDE's. In order to use LSP with your favorite language you'll need a language server to communicate with your editor of choice.&lt;/p&gt;

&lt;p&gt;In this article we'll focus on &lt;a href="https://github.com/haskell/haskell-language-server" rel="noopener noreferrer"&gt;haskell's language server&lt;/a&gt;. Not long ago the language server of choice used to be &lt;code&gt;hie&lt;/code&gt; but now it's deprecated.&lt;/p&gt;

&lt;p&gt;So let's get started! Assuming you have Haskell Stack up and running:&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="nv"&gt;$ &lt;/span&gt;stack &lt;span class="nb"&gt;install &lt;/span&gt;ghcid hspec-discover &lt;span class="c"&gt;# optional but great&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;git clone https://github.com/haskell/haskell-language-server &lt;span class="nt"&gt;--recurse-submodules&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;haskell-language-server
&lt;span class="nv"&gt;$ &lt;/span&gt;stack ./install.hs &lt;span class="nb"&gt;help&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;stack ./install.hs hls
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The binaries we'll be at the usual place: &lt;code&gt;~/.local/bin&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Right, but how do I use it? Well it depends on your editor. Let me show you how I do it in my &lt;code&gt;.vimrc&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight viml"&gt;&lt;code&gt;Plug &lt;span class="s1"&gt;'prabirshrestha/vim-lsp'&lt;/span&gt;
Plug &lt;span class="s1"&gt;'prabirshrestha/asyncomplete.vim'&lt;/span&gt;
Plug &lt;span class="s1"&gt;'prabirshrestha/asyncomplete-lsp.vim'&lt;/span&gt;
Plug &lt;span class="s1"&gt;'mattn/vim-lsp-settings'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Please read their documentation!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight viml"&gt;&lt;code&gt;&lt;span class="c"&gt;" vim-lsp-settings won't detect hls automatically as of today (2020-10-26). Let's teach it:&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;executable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'haskell-language-server-wrapper'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
  &lt;span class="k"&gt;au&lt;/span&gt; &lt;span class="nb"&gt;User&lt;/span&gt; lsp_setup &lt;span class="k"&gt;call&lt;/span&gt; &lt;span class="nb"&gt;lsp&lt;/span&gt;#register_server&lt;span class="p"&gt;({&lt;/span&gt;
&lt;span class="se"&gt;      \&lt;/span&gt; &lt;span class="s1"&gt;'name'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'haskell-language-server-wrapper'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="se"&gt;      \&lt;/span&gt; &lt;span class="s1"&gt;'cmd'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;server_info&lt;span class="p"&gt;-&amp;gt;[&lt;/span&gt;&lt;span class="s1"&gt;'haskell-language-server-wrapper'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'--lsp'&lt;/span&gt;&lt;span class="p"&gt;]},&lt;/span&gt;
&lt;span class="se"&gt;      \&lt;/span&gt; &lt;span class="s1"&gt;'whitelist'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'haskell'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="se"&gt;      \&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="k"&gt;endif&lt;/span&gt;

&lt;span class="c"&gt;" My Mappings&lt;/span&gt;
&lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt; &lt;span class="nv"&gt;s:on_lsp_buffer_enabled&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; abort
    &lt;span class="k"&gt;setlocal&lt;/span&gt; &lt;span class="nb"&gt;omnifunc&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;lsp&lt;/span&gt;#&lt;span class="nb"&gt;complete&lt;/span&gt;
    &lt;span class="k"&gt;setlocal&lt;/span&gt; &lt;span class="nb"&gt;signcolumn&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;yes
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;exists&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'+tagfunc'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="k"&gt;setlocal&lt;/span&gt; &lt;span class="nb"&gt;tagfunc&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;lsp&lt;/span&gt;#&lt;span class="nb"&gt;tagfunc&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="k"&gt;endif&lt;/span&gt;
    nmap &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;gd&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;plug&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="nb"&gt;lsp&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt;definition&lt;span class="p"&gt;)&lt;/span&gt;
    nmap &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;gr&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;plug&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="nb"&gt;lsp&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt;references&lt;span class="p"&gt;)&lt;/span&gt;
    nmap &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; gf &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;plug&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="nb"&gt;lsp&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt;code&lt;span class="p"&gt;-&lt;/span&gt;action&lt;span class="p"&gt;)&lt;/span&gt;
    nmap &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; gi &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;plug&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="nb"&gt;lsp&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt;implementation&lt;span class="p"&gt;)&lt;/span&gt;
    nmap &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; gt &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;plug&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="nb"&gt;lsp&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt;definition&lt;span class="p"&gt;)&lt;/span&gt;
    nmap &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;F2&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;plug&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="nb"&gt;lsp&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="nb"&gt;rename&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    nmap &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="k"&gt;g&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;Plug&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="nb"&gt;lsp&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="k"&gt;previous&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt;diagnostic&lt;span class="p"&gt;)&lt;/span&gt;
    nmap &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="k"&gt;g&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;Plug&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="nb"&gt;lsp&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="k"&gt;next&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt;diagnostic&lt;span class="p"&gt;)&lt;/span&gt;
    nmap &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; K &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;plug&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="nb"&gt;lsp&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt;hover&lt;span class="p"&gt;)&lt;/span&gt;
    xmap &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;f&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;plug&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="nb"&gt;lsp&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt;document&lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt;format&lt;span class="p"&gt;)&lt;/span&gt;
    nmap &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;F5&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;plug&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="nb"&gt;lsp&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt;code&lt;span class="p"&gt;-&lt;/span&gt;lens&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c"&gt;" buffer format on save&lt;/span&gt;
    &lt;span class="c"&gt;" autocmd BufWritePre &amp;lt;buffer&amp;gt; LspDocumentFormatSync&lt;/span&gt;
&lt;span class="k"&gt;endfunction&lt;/span&gt;

&lt;span class="c"&gt;" Decorations&lt;/span&gt;
augroup lsp_install
    &lt;span class="k"&gt;au&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;g:lsp_signs_enabled&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;         " enable signs
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;g:lsp_diagnostics_echo_cursor&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt; " enable echo under &lt;span class="nb"&gt;cursor&lt;/span&gt; when &lt;span class="k"&gt;in&lt;/span&gt; normal &lt;span class="k"&gt;mode&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;g:lsp_signs_error&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s1"&gt;'text'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'✗'&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="c"&gt;" let g:lsp_signs_warning = {'text': '‼', 'icon': '/path/to/some/icon'} " icons require GUI&lt;/span&gt;
    &lt;span class="c"&gt;" let g:lsp_signs_hint = {'icon': '/path/to/some/other/icon'} " icons require GUI&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;g:lsp_signs_warning&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s1"&gt;'text'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'‼'&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;g:lsp_highlight_references_enabled&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
    &lt;span class="nb"&gt;highlight&lt;/span&gt; link LspErrorText GruvboxRedSign " requires gruvbox
    &lt;span class="nb"&gt;highlight&lt;/span&gt; clear LspWarningLine
    &lt;span class="c"&gt;" highlight lspReference ctermfg=red guifg=red ctermbg=green guibg=green&lt;/span&gt;
    &lt;span class="nb"&gt;highlight&lt;/span&gt; lspReference guibg&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="mh"&gt;#303010&lt;/span&gt;

    &lt;span class="c"&gt;" call s:on_lsp_buffer_enabled only for languages that has the server registered.&lt;/span&gt;
    autocmd &lt;span class="nb"&gt;User&lt;/span&gt; lsp_buffer_enabled &lt;span class="k"&gt;call&lt;/span&gt; &lt;span class="nv"&gt;s:on_lsp_buffer_enabled&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
augroup END
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The first time you start vim with a Haskell file it'll take a while (you can check vim-lsp's status with &lt;code&gt;:LspStatus&lt;/code&gt;). As soon as a left margin (1 character wide) shows up, you're good to go!&lt;/p&gt;

&lt;p&gt;Now your Vim is an LSP powerhouse:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Hover:&lt;/li&gt;
&lt;/ul&gt;

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

&lt;ul&gt;
&lt;li&gt;Auto-complete:&lt;/li&gt;
&lt;/ul&gt;

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

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

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

</description>
      <category>haskell</category>
      <category>vim</category>
      <category>lsp</category>
    </item>
  </channel>
</rss>
