<?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: Paul</title>
    <description>The latest articles on DEV Community by Paul (@pcvonz).</description>
    <link>https://dev.to/pcvonz</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%2F91662%2F521a2996-5264-42fa-81bd-65a04a84d2e3.jpeg</url>
      <title>DEV Community: Paul</title>
      <link>https://dev.to/pcvonz</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/pcvonz"/>
    <language>en</language>
    <item>
      <title>I²C on the Pinephone</title>
      <dc:creator>Paul</dc:creator>
      <pubDate>Wed, 05 May 2021 04:40:03 +0000</pubDate>
      <link>https://dev.to/pcvonz/i-c-on-the-pinephone-5090</link>
      <guid>https://dev.to/pcvonz/i-c-on-the-pinephone-5090</guid>
      <description>&lt;h1&gt;
  
  
  Overview
&lt;/h1&gt;

&lt;p&gt;The &lt;a href="https://www.pine64.org/pinephone/" rel="noopener noreferrer"&gt;Pinephone&lt;/a&gt; is an open source smartphone that runs Linux. It's a really neat device and will hopefully be suitable as a daily driver smartphone in the near future, but for now it's very pleasant to hack on. Short surface level overview of the device &lt;a href="https://www.youtube.com/watch?v=fCKMxzz9cjs" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The below example is a little contrived, but hopefully sheds some light on connecting external peripherals to the Pinephone. I'm also fairly new to embedded stuff, D-bus, and still shaky on my Rust knowledge, so critique on a better way to implement all this is very welcome.&lt;/p&gt;

&lt;h2&gt;
  
  
  I²C
&lt;/h2&gt;

&lt;p&gt;I²C is a common method for interfacing with embedded peripherals. It's a fairly simple communication method. For a deeper dive checkout out the &lt;a href="https://docs.rust-embedded.org/discovery/14-i2c/index.html" rel="noopener noreferrer"&gt;Embedded Rust Discovery Book&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Embedded rust
&lt;/h2&gt;

&lt;p&gt;In order to understand how the driver works we need to understand a little bit about the embedded rust ecosystem. &lt;code&gt;embedded-hal&lt;/code&gt; is a set of traits which can be used to create platform-agnostic drivers. The &lt;code&gt;SSD1306&lt;/code&gt; targets &lt;code&gt;embedded-hal&lt;/code&gt;, so any hal that implements the &lt;code&gt;embedded-hal&lt;/code&gt; traits will be able to use the driver. In order to use &lt;code&gt;SSD1306&lt;/code&gt; driver on our Pinephone we'll take advantage of the &lt;code&gt;linux-embeddedhal&lt;/code&gt; crate.&lt;/p&gt;

&lt;h1&gt;
  
  
  I2c on the pinephone
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Accessing the pogo pins
&lt;/h2&gt;

&lt;p&gt;You'll need some way to connect your device to the Pinephone. The easiest method is to just purchase a &lt;a href="https://pine64.com/product/pinephone-flex-break-out-board/?v=0446c16e2e66" rel="noopener noreferrer"&gt;breakout board&lt;/a&gt;. But, there are &lt;a href="https://www.youtube.com/watch?v=lFsQpd0bLTY" rel="noopener noreferrer"&gt;other ways&lt;/a&gt; to access these pins. I used the breakout board &lt;a href="https://github.com/jnavarro7/pinephone_flex_breakout_board" rel="noopener noreferrer"&gt;from this repo&lt;/a&gt; and ordered them from OSH Park. There is some soldering required.&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%2F15i6qlrjs7sxdp9f2z4y.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F15i6qlrjs7sxdp9f2z4y.jpg" alt="Pinephone back"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Connect the display
&lt;/h2&gt;

&lt;p&gt;Connecting the display is pretty straightforward. &lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwiki.pine64.org%2Fimages%2Fthumb%2Fe%2Fe1%2FPinephone_pogo.png%2F400px-Pinephone_pogo.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%2Fwiki.pine64.org%2Fimages%2Fthumb%2Fe%2Fe1%2FPinephone_pogo.png%2F400px-Pinephone_pogo.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;One you've connected your breakout you just need to match up the pins (&lt;code&gt;GND&lt;/code&gt; &lt;code&gt;VCC&lt;/code&gt; &lt;code&gt;SCL&lt;/code&gt; &lt;code&gt;SDA&lt;/code&gt;) to the display. &lt;/p&gt;
&lt;h2&gt;
  
  
  I²C on Linux
&lt;/h2&gt;

&lt;p&gt;🚨 You may need to enable the proper kernel driver. I'm using Arch Linux on my pinephone, which appears to have the I²C kernel module already enabled. &lt;/p&gt;

&lt;p&gt;Make sure you have have the &lt;code&gt;i2cdetect&lt;/code&gt; utility installed. On arch linux the utility is in the &lt;code&gt;i2c-tools&lt;/code&gt; package. With that tool installed run &lt;code&gt;i2cdetect -l&lt;/code&gt; to print out all the i2c devices:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;i2c-3   unknown         mv64xxx_i2c adapter                     N/A
i2c-1   unknown         mv64xxx_i2c adapter                     N/A
i2c-4   unknown         i2c-csi                                 N/A
i2c-2   unknown         mv64xxx_i2c adapter                     N/A
i2c-0   unknown         DesignWare HDMI                         N/A
i2c-5   unknown         i2c-2-mux (chan_id 0)                   N/A
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each I²C device will have an address we use to interface with it. The &lt;code&gt;SSD1306&lt;/code&gt; by default has an address of &lt;code&gt;3C&lt;/code&gt;. In order to figure out which I²C device we need to communicate with, we can probe each of the interfaces. Here is my output after probing device 3&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ i2cdetect 3
 0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f  
00:                         -- -- -- -- -- -- -- --    
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --    
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --    
30: -- -- -- -- -- -- -- -- -- -- -- -- 3c -- -- --    
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --    
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --    
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;/dev/i2c-3&lt;/code&gt; appears to be the interface the SSD1306 display is connected to. With that knowledge we can start programming some Rust!&lt;/p&gt;

&lt;h2&gt;
  
  
  Rust!
&lt;/h2&gt;

&lt;p&gt;Create a new Rust project. Use &lt;a href="https://rustup.rs/" rel="noopener noreferrer"&gt;rustup&lt;/a&gt; if you don't already have it installed. &lt;/p&gt;

&lt;p&gt;&lt;code&gt;cargo new i2c-test &amp;amp;&amp;amp; cd i2c-test&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Modify &lt;code&gt;Cargo.toml&lt;/code&gt; to add the dependencies we need:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# ...Omitted

[dependencies]  
ssd1306 = "0.5.2"  
linux-embedded-hal = "0.3.0"  
embedded-graphics = "0.6.2"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And then modify &lt;code&gt;src/main.rs&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;embedded_graphics&lt;/span&gt;&lt;span class="p"&gt;::{&lt;/span&gt;  
&lt;span class="err"&gt;   &lt;/span&gt;&lt;span class="nn"&gt;fonts&lt;/span&gt;&lt;span class="p"&gt;::{&lt;/span&gt;&lt;span class="n"&gt;Font6x8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;  
&lt;span class="err"&gt;   &lt;/span&gt;&lt;span class="nn"&gt;pixelcolor&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;BinaryColor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  
&lt;span class="err"&gt;   &lt;/span&gt;&lt;span class="nn"&gt;prelude&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  
&lt;span class="err"&gt;   &lt;/span&gt;&lt;span class="nn"&gt;style&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;TextStyleBuilder&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  
&lt;span class="p"&gt;};&lt;/span&gt;  
&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;ssd1306&lt;/span&gt;&lt;span class="p"&gt;::{&lt;/span&gt;&lt;span class="nn"&gt;mode&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;GraphicsMode&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nn"&gt;prelude&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="err"&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;Builder&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;I2CDIBuilder&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;  
&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;core&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Write&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  
&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;linux_embedded_hal&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;I2cdev&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  

&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;main&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="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;i2c&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;I2cdev&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/dev/i2c-3"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;.unwrap&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// Replace with the proper interface!&lt;/span&gt;
&lt;span class="err"&gt;   &lt;/span&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;interface&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;I2CDIBuilder&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&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="n"&gt;i2c&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;  
&lt;span class="err"&gt;   &lt;/span&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;disp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;GraphicsMode&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Builder&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;  
&lt;span class="err"&gt;       &lt;/span&gt;&lt;span class="nf"&gt;.size&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;DisplaySize128x64&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  
&lt;span class="err"&gt;       &lt;/span&gt;&lt;span class="nf"&gt;.connect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;.into&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;  
&lt;span class="err"&gt;   &lt;/span&gt;&lt;span class="n"&gt;disp&lt;/span&gt;&lt;span class="nf"&gt;.init&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.unwrap&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;  

&lt;span class="err"&gt;   &lt;/span&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;text_style&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;TextStyleBuilder&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Font6x8&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  
&lt;span class="err"&gt;       &lt;/span&gt;&lt;span class="nf"&gt;.text_color&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;BinaryColor&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;On&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  
&lt;span class="err"&gt;       &lt;/span&gt;&lt;span class="nf"&gt;.build&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;  

&lt;span class="err"&gt;   &lt;/span&gt;&lt;span class="nn"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Hello world!"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nn"&gt;Point&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;zero&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;  
&lt;span class="err"&gt;       &lt;/span&gt;&lt;span class="nf"&gt;.intostyled&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text_style&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  
&lt;span class="err"&gt;       &lt;/span&gt;&lt;span class="nf"&gt;.draw&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;disp&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;  

&lt;span class="err"&gt;   &lt;/span&gt;&lt;span class="n"&gt;disp&lt;/span&gt;&lt;span class="nf"&gt;.flush&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.unwrap&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;  

&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Before we run this code let's take a step back and look at the permissions on the &lt;code&gt;i2c-#&lt;/code&gt; devices.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ ls -l /dev/ | grep i2c

crw-------  1 root  root    89,   0 May  4 12:09 i2c-0  
crw-------  1 root  root    89,   1 May  4 12:09 i2c-1  
crw-------  1 root  root    89,   2 May  4 12:09 i2c-2  
crw-------  1 root  root    89,   3 May  4 12:09 i2c-3  
crw-------  1 root  root    89,   4 May  4 12:09 i2c-4  
crw-------  1 root  root    89,   5 May  4 12:09 i2c-5
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These devices are both owned by root and in the group root. If we try to run our rust code right now, the code will fail because our user lacks permission to read from the I²C device. A quick fix is to run:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;chown $(whoami) /dev/i2c-#&lt;/code&gt;  (replace &lt;code&gt;#&lt;/code&gt; with the I²C  # you found from the previous section).&lt;/p&gt;

&lt;p&gt;Now we can run: &lt;code&gt;cargo run&lt;/code&gt; and you should see the display light up with &lt;code&gt;Hello world!&lt;/code&gt;.&lt;/p&gt;

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

&lt;p&gt;📝 There isn't anything Pinephone specific about this code. You should be able to run this exact program (provided that it references the right device) on something like a raspberry pi.&lt;/p&gt;

&lt;h1&gt;
  
  
  Let's do something more elaborate
&lt;/h1&gt;

&lt;p&gt;Wouldn't it be cool, although maybe a little unnecessary if we could display the cell signal on our new OLED screen? Let's do it!&lt;/p&gt;

&lt;h2&gt;
  
  
  D-bus modem manager
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://en.wikipedia.org/wiki/D-Bus" rel="noopener noreferrer"&gt;D-bus&lt;/a&gt; is a messaging middleware for communicating between multiple processes. What we're interested in is the &lt;code&gt;ModemManager&lt;/code&gt; D-bus interface. &lt;a href="https://www.freedesktop.org/software/ModemManager/doc/latest/ModemManager/" rel="noopener noreferrer"&gt;Take a look at the modemmanager documenation&lt;/a&gt; to get an idea of what you can do with this interface. &lt;a href="https://wiki.gnome.org/Apps/DFeet" rel="noopener noreferrer"&gt;D-Feet&lt;/a&gt; is a great little app that can list all the different interfaces you can connect to and all the methods and properties they provide. &lt;/p&gt;

&lt;h2&gt;
  
  
  D-bus and Rust
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Generating our D-bus interface
&lt;/h3&gt;

&lt;p&gt;To actually interact with D-bus we'll generate the rust code necessary using &lt;a href="https://crates.io/crates/dbus-codegen/" rel="noopener noreferrer"&gt;dbus-codegen&lt;/a&gt;. This is surprisingly easy once you have all the pieces. First install the utility:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;cargo install dbus-codegen&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;And then run the utility. My command ended up looking something like this:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;dbus-codegen-rust -s -g -m None -d org.freedesktop.ModemManager1 -p /org/freedesktop/ModemManager1/Modem/0 &amp;gt; src/modemmanager.rs&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Printing out the cell signal level
&lt;/h3&gt;

&lt;p&gt;At this point your rust directory should look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;├── Cargo.lock  
├── Cargo.toml  
└── src  
    ├── main.rs  
    └── modemmanager.rs
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;First, let's update &lt;code&gt;Cargo.toml&lt;/code&gt; with the &lt;code&gt;dbus&lt;/code&gt; dependency&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[dependencies]
dbus = "0.9.2"
# Extra deps omitted!
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, we can get the signal level with the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;mod&lt;/span&gt; &lt;span class="n"&gt;modemmanager&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="c1"&gt;//...&lt;/span&gt;
&lt;span class="c1"&gt;// Omitted extra packages!&lt;/span&gt;
&lt;span class="c1"&gt;//...&lt;/span&gt;
&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;dbus&lt;/span&gt;&lt;span class="p"&gt;::{&lt;/span&gt;&lt;span class="nn"&gt;blocking&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Connection&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="nb"&gt;Box&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;dyn&lt;/span&gt; &lt;span class="nn"&gt;std&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;error&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Notice that we used `new_system`&lt;/span&gt;
    &lt;span class="c1"&gt;// This connects to the `system` dbus&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;conn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Connection&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new_system&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// Second, create a wrapper struct around the connection that makes it easy&lt;/span&gt;
    &lt;span class="c1"&gt;// to send method calls to a specific destination and path.&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;proxy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="nf"&gt;.with_proxy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"org.freedesktop.ModemManager1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"/org/freedesktop/ModemManager1/Modem/0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nn"&gt;Duration&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;from_millis&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5000&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

    &lt;span class="c1"&gt;// Import our generated interface!&lt;/span&gt;
    &lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;modemmanager&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;OrgFreedesktopDBusProperties&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// Use d-feet to make sure that this is the same on your system.&lt;/span&gt;
    &lt;span class="c1"&gt;// Look for the `SignalQuality` property&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;signal_quality&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;  &lt;span class="nb"&gt;Box&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;dyn&lt;/span&gt; &lt;span class="nn"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;RefArg&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;proxy&lt;/span&gt;&lt;span class="nf"&gt;.get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"org.freedesktop.ModemManager1.Modem"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"SignalQuality"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// Cast the signal quality to an i64, yes this has some code smell, but we're just hacking this :)&lt;/span&gt;
    &lt;span class="c1"&gt;// in here&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;signal&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;i64&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;signal_quality&lt;/span&gt;
        &lt;span class="nf"&gt;.as_iter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="nf"&gt;.unwrap&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="nf"&gt;.next&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="nf"&gt;.unwrap&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="nf"&gt;.as_i64&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="nf"&gt;.unwrap&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="c1"&gt;// ...&lt;/span&gt;
    &lt;span class="c1"&gt;// I2C code from the previous omitted&lt;/span&gt;
    &lt;span class="c1"&gt;// ...&lt;/span&gt;
    &lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(())&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;&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%2Fqsmckggc52nmnq3egib4.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqsmckggc52nmnq3egib4.jpg" alt="IMG_20210504_173254"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  What next?
&lt;/h1&gt;

&lt;p&gt;Look at the methods generated by &lt;code&gt;dbus-codegen&lt;/code&gt;. Instead of just running this method and closing we could listen for the &lt;code&gt;PropertiesChanged&lt;/code&gt; signal to update the display. Or look at the existing &lt;a href="https://crates.io/keywords/embedded-hal-driver" rel="noopener noreferrer"&gt;embedded hal drivers&lt;/a&gt; and pick up some new hardware to play with. Any of the sensors listed there should work just as easily as the SSD1306 display. If you have something which doesn't have a driver in Rust yet, well &lt;a href="https://hboeving.dev/blog/rust-2c-driver-p1/" rel="noopener noreferrer"&gt;writing embedded drivers in rust isn't that hard&lt;/a&gt;. Give it a try.&lt;/p&gt;

&lt;p&gt;The Pinephone may still be a little rough to use as a daily driver, but it has a lot of potential and hackability. I hope more people invest in this device and we start seeing some more interesting projects.&lt;/p&gt;

&lt;h1&gt;
  
  
  Misc Sources
&lt;/h1&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://wiki.pine64.org/index.php/PinePhone#Pogo_pins" rel="noopener noreferrer"&gt;https://wiki.pine64.org/index.php/PinePhone#Pogo_pins&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.rust-embedded.org/book/portability/index.html" rel="noopener noreferrer"&gt;https://docs.rust-embedded.org/book/portability/index.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/diwic/dbus-rs/blob/master/dbus/examples/argument_guide.md" rel="noopener noreferrer"&gt;https://github.com/diwic/dbus-rs/blob/master/dbus/examples/argument_guide.md&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/diwic/dbus-rs" rel="noopener noreferrer"&gt;https://github.com/diwic/dbus-rs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.freedesktop.org/software/ModemManager/doc/latest/ModemManager/" rel="noopener noreferrer"&gt;https://www.freedesktop.org/software/ModemManager/doc/latest/ModemManager/&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>pinephone</category>
      <category>rust</category>
      <category>linux</category>
    </item>
    <item>
      <title>Unsubscribe from everyone 🎉</title>
      <dc:creator>Paul</dc:creator>
      <pubDate>Mon, 15 Jun 2020 19:35:39 +0000</pubDate>
      <link>https://dev.to/pcvonz/unsubscribe-from-everyone-20m4</link>
      <guid>https://dev.to/pcvonz/unsubscribe-from-everyone-20m4</guid>
      <description>&lt;p&gt;I found that I was subscribed to 50 users that I didn't remember following (No wonder I'm getting so many notifications!). I looked into the API and found that there wasn't a way to unsubscribe from everyone. No matter, we can do it from the followers list with a little javascript:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;querySelectorAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;.follow-action-button&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;el&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;el&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;click&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run that in &lt;code&gt;Dashboard &amp;gt; following &amp;gt; uers&lt;/code&gt; via the console to unfollow everyone. Now you should have a squeaky clean feed ✨ 👍&lt;/p&gt;

</description>
      <category>meta</category>
      <category>javascript</category>
    </item>
    <item>
      <title>jq + httpie = 💓</title>
      <dc:creator>Paul</dc:creator>
      <pubDate>Sun, 14 Jun 2020 04:20:23 +0000</pubDate>
      <link>https://dev.to/pcvonz/jq-httpie-1nl6</link>
      <guid>https://dev.to/pcvonz/jq-httpie-1nl6</guid>
      <description>&lt;h1&gt;
  
  
  Setting up
&lt;/h1&gt;

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

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://stedolan.github.io/jq/"&gt;jq&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://httpie.org/"&gt;httpie&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For this demo, we'll connect to the &lt;a href="https://developer.spotify.com/documentation/web-api/"&gt;Spotify api&lt;/a&gt;. Create a new Spotify application &lt;a href="https://developer.spotify.com/dashboard/applications"&gt;here&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Client credentials flow
&lt;/h2&gt;

&lt;p&gt;There is a great little plugin for httpie which makes this very easy. It needed a little update. So, for now I'll link &lt;a href="https://github.com/pcvonz/httpie-oauth2"&gt;my fork&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;To install just clone the repo and run &lt;code&gt;sudo python setup.py install&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  OAuth2 flow
&lt;/h2&gt;

&lt;p&gt;Spotify uses OAuth2. In order to get your access token to make requests relevant to your spotify account, you'll need to acquire an access token. I used this cli tool written in go to accomplish this. You can find that &lt;a href="https://github.com/dcarley/oauth2-cli"&gt;here&lt;/a&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="n"&gt;oauth2&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;cli&lt;/span&gt; &lt;span class="err"&gt;\&lt;/span&gt;
  &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="n"&gt;CLIENT_ID&lt;/span&gt; &lt;span class="err"&gt;\&lt;/span&gt;
  &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;secret&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="n"&gt;CLIENT_SECRET&lt;/span&gt; &lt;span class="err"&gt;\&lt;/span&gt;
  &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;auth&lt;/span&gt; &lt;span class="n"&gt;https&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="c"&gt;//accounts.spotify.com/authorize \&lt;/span&gt;
  &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;token&lt;/span&gt; &lt;span class="n"&gt;https&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="c"&gt;//accounts.spotify.com/api/token \&lt;/span&gt;
  &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;scope&lt;/span&gt; &lt;span class="s"&gt;"user-read-private user-read-email user-library-read"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Making some requests
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Downloading artist images from a search and then opening them
&lt;/h2&gt;

&lt;p&gt;First, we'll make some requests that only require the client credentials flow.&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;#!bin/bash&lt;/span&gt;
&lt;span class="nv"&gt;AUTH_URL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"https://accounts.spotify.com/api"&lt;/span&gt;
&lt;span class="nv"&gt;BASE_URL_API&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"https://api.spotify.com/v1"&lt;/span&gt;
&lt;span class="nv"&gt;CLIENT_ID&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;cat &lt;/span&gt;client_id&lt;span class="si"&gt;)&lt;/span&gt;
&lt;span class="nv"&gt;CLIENT_SECRET&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;cat &lt;/span&gt;client_secret&lt;span class="si"&gt;)&lt;/span&gt;

http &lt;span class="nt"&gt;--print&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"b"&lt;/span&gt; &lt;span class="nt"&gt;--auth-type&lt;/span&gt; oauth2 &lt;span class="se"&gt;\&lt;/span&gt;
              &lt;span class="nt"&gt;--auth&lt;/span&gt; &lt;span class="nv"&gt;$CLIENT_ID&lt;/span&gt;:&lt;span class="nv"&gt;$CLIENT_SECRET&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
              &lt;span class="nt"&gt;--issuer-uri&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$AUTH_URL&lt;/span&gt;&lt;span class="s2"&gt;/token"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
              &lt;span class="nt"&gt;--scope&lt;/span&gt; &lt;span class="s2"&gt;"user-read-private"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
              GET &lt;span class="nv"&gt;$BASE_URL_API&lt;/span&gt;/search &lt;span class="nv"&gt;q&lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="s2"&gt;"Sophie Hutchings"&lt;/span&gt; &lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="s2"&gt;"artist"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should see a big chunk of JSON as output. Couple things to note here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;CLIENT_ID=$(cat client_id)&lt;/code&gt;: This is &lt;a href="https://www.gnu.org/software/bash/manual/html_node/Command-Substitution.html"&gt;command substitution&lt;/a&gt;. There is a file in the directory I'm running this script that contains my client id.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;--print="b"&lt;/code&gt; is telling httpie to print the body of the request only (we'll pipe the body into &lt;code&gt;jq&lt;/code&gt; later). Other arguments to &lt;code&gt;--print&lt;/code&gt; are:

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;H&lt;/code&gt;: Request headers&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;h&lt;/code&gt; Response headers&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;B&lt;/code&gt; request body&lt;/li&gt;
&lt;/ul&gt;


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

&lt;p&gt;Let's pipe this into &lt;code&gt;jq&lt;/code&gt; and just get a list of images from each artist.&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;# Beginning lines omitted&lt;/span&gt;

&lt;span class="c"&gt;## Simple search&lt;/span&gt;
&lt;span class="nv"&gt;ARTISTS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;http &lt;span class="nt"&gt;--print&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"b"&lt;/span&gt; &lt;span class="nt"&gt;--auth-type&lt;/span&gt; oauth2 &lt;span class="se"&gt;\&lt;/span&gt;
     &lt;span class="nt"&gt;--auth&lt;/span&gt; &lt;span class="nv"&gt;$CLIENT_ID&lt;/span&gt;:&lt;span class="nv"&gt;$CLIENT_SECRET&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
     &lt;span class="nt"&gt;--issuer-uri&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$AUTH_URL&lt;/span&gt;&lt;span class="s2"&gt;/token"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
     &lt;span class="nt"&gt;--scope&lt;/span&gt; &lt;span class="s2"&gt;"user-read-private"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
     GET &lt;span class="nv"&gt;$BASE_URL_API&lt;/span&gt;/search &lt;span class="nv"&gt;q&lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="s2"&gt;"Sophie Hutchings"&lt;/span&gt; &lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="s2"&gt;"artist"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;

&lt;span class="c"&gt;# List of artist images&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nv"&gt;$ARTISTS&lt;/span&gt; | jq &lt;span class="s1"&gt;'.artists.items | map(.images | map(.url)) | flatten(1)'&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This chunk begins with more command substitution to store the response from before into the &lt;code&gt;ARTISTS&lt;/code&gt; variable. The contents of the variable is &lt;a href="https://en.wikipedia.org/wiki/Pipeline_(Unix)"&gt;piped&lt;/a&gt; into &lt;code&gt;jq&lt;/code&gt; to print a flat list of all the images from the artist we searched on. Let's cover some of the &lt;code&gt;jq&lt;/code&gt; functions we used:&lt;/p&gt;

&lt;p&gt;The simplest filter we used is the "Object Identifier-Index" &lt;code&gt;.artists.items&lt;/code&gt;. This simply accesses a property within a JSON object.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;artists&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;href&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://api.spotify.com/v1/search?query=Bad&amp;amp;type=artist&amp;amp;offset=0&amp;amp;limit=20&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;items&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[...]&lt;/span&gt; &lt;span class="c1"&gt;// &amp;lt;--- .artists.items is grabbing this array&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;items&lt;/code&gt; array is piped into the &lt;a href="https://en.wikipedia.org/wiki/Map_(higher-order_function)"&gt;map&lt;/a&gt; function. The map function iterates over each item returning a new array of image urls. Let's look at the JSON at this point:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"https://i.scdn.co/image/23009960c33ef08d5973440cca17985a6c70a515"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"https://i.scdn.co/image/8ff3e392402169f239bce72b3d80c701b75150b8"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"https://i.scdn.co/image/624dd15f5bdcc1bae5fa47739601f3e0be62ebda"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"https://i.scdn.co/image/23009960c33ef08d5973440cca17985a6c70a515"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"https://i.scdn.co/image/8ff3e392402169f239bce72b3d80c701b75150b8"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"https://i.scdn.co/image/624dd15f5bdcc1bae5fa47739601f3e0be62ebda"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;An array of arrays isn't useful for what we're doing next. So we use &lt;code&gt;flatten&lt;/code&gt; to return a flat array of all the image URLs.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="s2"&gt;"https://i.scdn.co/image/23009960c33ef08d5973440cca17985a6c70a515"&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="s2"&gt;"https://i.scdn.co/image/8ff3e392402169f239bce72b3d80c701b75150b8"&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="s2"&gt;"https://i.scdn.co/image/624dd15f5bdcc1bae5fa47739601f3e0be62ebda"&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="s2"&gt;"https://i.scdn.co/image/23009960c33ef08d5973440cca17985a6c70a515"&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="s2"&gt;"https://i.scdn.co/image/8ff3e392402169f239bce72b3d80c701b75150b8"&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="s2"&gt;"https://i.scdn.co/image/624dd15f5bdcc1bae5fa47739601f3e0be62ebda"&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Nice! Now, let's try to download these and then open them.&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;# Previous lines omitted&lt;/span&gt;

&lt;span class="nv"&gt;IMAGE_URLS&lt;/span&gt;&lt;span class="o"&gt;=&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;$ARTISTS&lt;/span&gt; | jq &lt;span class="nt"&gt;-r&lt;/span&gt; &lt;span class="s1"&gt;'.artists.items | map(.images | map(.url)) | flatten(1) | @csv'&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;

&lt;span class="c"&gt;# Download and open all the images from a search on artists&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nv"&gt;$IMAGE_URLS&lt;/span&gt; | &lt;span class="nb"&gt;tr&lt;/span&gt; &lt;span class="s1"&gt;','&lt;/span&gt; &lt;span class="s1"&gt;'\n'&lt;/span&gt; | &lt;span class="se"&gt;\&lt;/span&gt;
   xargs &lt;span class="nt"&gt;-I&lt;/span&gt; % sh &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s1"&gt;'wget % &amp;amp;&amp;amp; xdg-open %'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--1kXSg269--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/71gz6psc6hcirgmshgm5.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--1kXSg269--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/71gz6psc6hcirgmshgm5.gif" alt="Jq images"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We modified a couple things in our jq command. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;-r&lt;/code&gt;: raw output. In this example it omits &lt;code&gt;"&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;@csv&lt;/code&gt;: Omits csv for further processing. Only works on arrays.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The csv output by jq is piped into &lt;a href="https://en.wikipedia.org/wiki/Tr_(Unix)"&gt;tr&lt;/a&gt;. The tr command replaces &lt;code&gt;,&lt;/code&gt; with new lines. Each line is piped into &lt;a href="https://en.wikipedia.org/wiki/Xargs"&gt;xargs&lt;/a&gt;. Let's dissect the xargs command:&lt;/p&gt;

&lt;p&gt;-&lt;code&gt;-I&lt;/code&gt;: the replace-str command. The argument is the string that will be replaced by the value from standard input in the final command. So &lt;code&gt;%&lt;/code&gt; will turn into our image url. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;bash -c 'wget % &amp;amp;&amp;amp; xdg-open %'&lt;/code&gt;: Starts a new sub shell (each % is replaced by the image url)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;wget&lt;/code&gt;: Downloads files from the web&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;xdg-open&lt;/code&gt;: Opens a file or URL in the user's preferred application&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The result of running this should be a bunch of images being downloaded to your computer and then opened by whatever program is preferred by your user. &lt;/p&gt;

&lt;h2&gt;
  
  
  Inspecting your saved albums and printing all the tracks for each album
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!bin/bash&lt;/span&gt;
&lt;span class="nv"&gt;AUTH_URL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"https://accounts.spotify.com/api"&lt;/span&gt;
&lt;span class="nv"&gt;BASE_URL_API&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"https://api.spotify.com/v1"&lt;/span&gt;
&lt;span class="nv"&gt;CLIENT_ID&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;cat &lt;/span&gt;client_id&lt;span class="si"&gt;)&lt;/span&gt;
&lt;span class="nv"&gt;CLIENT_SECRET&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;cat &lt;/span&gt;client_secret&lt;span class="si"&gt;)&lt;/span&gt;

&lt;span class="c"&gt;# You'll have to run this first. Copy the access token to `auth_token` in the same directory as this script&lt;/span&gt;
&lt;span class="c"&gt;# oauth2-cli \&lt;/span&gt;
&lt;span class="c"&gt;#   -id $CLIENT_ID \&lt;/span&gt;
&lt;span class="c"&gt;#   -secret $CLIENT_SECRET \&lt;/span&gt;
&lt;span class="c"&gt;#   -auth https://accounts.spotify.com/authorize \&lt;/span&gt;
&lt;span class="c"&gt;#   -token https://accounts.spotify.com/api/token \&lt;/span&gt;
&lt;span class="c"&gt;#   -scope "user-library-read"&lt;/span&gt;

&lt;span class="c"&gt;# Get a list of albums from your library&lt;/span&gt;
&lt;span class="nv"&gt;ALBUMS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;http GET &lt;span class="nv"&gt;$BASE_URL_API&lt;/span&gt;/me/albums &lt;span class="se"&gt;\&lt;/span&gt;
  Authorization:&lt;span class="s2"&gt;"Bearer &lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;cat &lt;/span&gt;auth_token&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;

&lt;span class="c"&gt;# List saved albums from your spotify profile and their artists&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nv"&gt;$ALBUMS&lt;/span&gt; | jq &lt;span class="s1"&gt;'.items | map({ "name": .album.name, "artists": .album.artists | map(.name)})'&lt;/span&gt;

&lt;span class="c"&gt;# Get tracks from your albums&lt;/span&gt;
&lt;span class="nv"&gt;ALBUM_IDS&lt;/span&gt;&lt;span class="o"&gt;=&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;$ALBUMS&lt;/span&gt; | jq &lt;span class="nt"&gt;-r&lt;/span&gt; &lt;span class="s1"&gt;'.items | map(.album.id) | @tsv'&lt;/span&gt; &lt;span class="si"&gt;)&lt;/span&gt;

&lt;span class="c"&gt;## Separtes each album by a newline, for further processing and then make another request for each album to get a list of tracks&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nv"&gt;$ALBUM_IDS&lt;/span&gt; | &lt;span class="nb"&gt;tr&lt;/span&gt; &lt;span class="s1"&gt;' '&lt;/span&gt; &lt;span class="s1"&gt;'\n'&lt;/span&gt; | xargs &lt;span class="nt"&gt;-I&lt;/span&gt; % sh &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s1"&gt;'http --print="b" GET https://api.spotify.com/v1/albums/%/tracks \
  Authorization:"Bearer $(cat auth_token)" | jq ".items | map({ "name": .name, "artists": .artists | map(.name)})"'&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;Everything we covered in the previous section is used in here too! One difference is that we use map to return a list of objects instead. &lt;/p&gt;

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

&lt;p&gt;Using jq with httpie is powerful once you get the hang of using some of the linux utilities and idiosyncrasies of shell scripting. I'm still learning new stuff everyday. If you have any thoughts on how to improve this workflow, please share!&lt;/p&gt;

</description>
      <category>jq</category>
      <category>httpie</category>
      <category>bash</category>
      <category>linux</category>
    </item>
    <item>
      <title>Making your Vim easier to follow 👀</title>
      <dc:creator>Paul</dc:creator>
      <pubDate>Sat, 14 Mar 2020 22:10:50 +0000</pubDate>
      <link>https://dev.to/pcvonz/making-your-vim-easier-to-follow-2co2</link>
      <guid>https://dev.to/pcvonz/making-your-vim-easier-to-follow-2co2</guid>
      <description>&lt;p&gt;By default Vim is hard to follow for people other than the person driving. When pair programming or doing code review, the ability to follow along with the person editing is obviously super important. My coworkers get visibly exhausted when we view code on my machine. As much as I'd like to think it's because I'm incredibly fast with Vim (I am &lt;em&gt;pretty&lt;/em&gt; fast 🔥), it's more likely due to the fact that terminal Vim is just a little hard to keep up with for a few reasons.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Scrolling happens instantly, there is no smooth animation.&lt;/li&gt;
&lt;li&gt;The cursor tends to jump around wildly if you're watching a seasoned Vim user.&lt;/li&gt;
&lt;li&gt;Jumps between splits, buffers, tabs, etc. are hard to follow&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  A minimalistic GUI: Neovide
&lt;/h2&gt;

&lt;p&gt;Neovide is a very simplistic Gui around Neovim (the Vim fork with among many improvements, an emphasis on being embeddable). It adds a few nice features, but the killer one for me is the animated cursor:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--qn1MR0f7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/sg9pb94wq23k3nfr7i59.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--qn1MR0f7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/sg9pb94wq23k3nfr7i59.gif" alt="Neovide demo"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This solves so many pain points when anyone is watching a Vim user. It animates your cursor between every motion. Navigating between splits, buffers, the quickfix window, etc. &lt;/p&gt;

&lt;p&gt;And for bonus fun you can add &lt;a href="https://github.com/Kethku/neovide/wiki/Configuration#cursor-particles"&gt;particle effects&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  May hamper some of your usual workflows:
&lt;/h3&gt;

&lt;p&gt;📓 By default &lt;code&gt;&amp;lt;CR&amp;gt; V&lt;/code&gt; is not bound to paste to paste in Neovide. Instead, you can paste from the &lt;code&gt;+&lt;/code&gt; (clipboard) register: &lt;code&gt;["+]p&lt;/code&gt;, or in insert mode: &lt;code&gt;[&amp;lt;cr&amp;gt;r]+&lt;/code&gt;. &lt;/p&gt;

&lt;h2&gt;
  
  
  Smooth scrolling
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--y6hub_EM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/hp0mr6bn87akf6rwgh5p.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--y6hub_EM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/hp0mr6bn87akf6rwgh5p.gif" alt="Smooth scrolling"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Smooth scrolling is a lot easier on the eyes and makes it a lot less disorienting for your viewers when you're navigating a large file. Smooth scrolling has been discussed in the &lt;a href="https://github.com/Kethku/neovide/issues/62"&gt; Neovide issues &lt;/a&gt;, but isn't added yet. Instead, it is possible to get a nice smooth scrolling experience via a Vim plugin. This works in terminal Vim too: &lt;a href="https://github.com/psliwka/vim-smoothie"&gt;Vim Smoothie&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;These small changes can really improve the editing experience for yourself and for those following along. Happy Vimming!&lt;/p&gt;

</description>
      <category>vim</category>
      <category>neovim</category>
    </item>
    <item>
      <title>Covid 19 Updates from Vim, with Python!</title>
      <dc:creator>Paul</dc:creator>
      <pubDate>Fri, 13 Mar 2020 23:54:44 +0000</pubDate>
      <link>https://dev.to/pcvonz/covid-19-updates-from-vim-with-python-17g6</link>
      <guid>https://dev.to/pcvonz/covid-19-updates-from-vim-with-python-17g6</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--3nkEFzH9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/zwm5lnh9bm8tld3ykbcj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--3nkEFzH9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/zwm5lnh9bm8tld3ykbcj.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;br&gt;
This was just a fun (and morbid) way to experiment with hacking on vim with Python.&lt;/p&gt;

&lt;p&gt;If you have Vim compiled with Python and the &lt;a href="https://github.com/vim-airline/vim-airline"&gt;Airline&lt;/a&gt; plugin installed, you should be able to just plop this into your &lt;code&gt;vimrc&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;💡 There is an updated version that works asynchronously below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight viml"&gt;&lt;code&gt;&lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt; CovidUpdate&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="k"&gt;python3&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&amp;lt;&lt;/span&gt; EOF
from urllib &lt;span class="k"&gt;import&lt;/span&gt; request
&lt;span class="k"&gt;import&lt;/span&gt; json
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="k"&gt;vim&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; getCases&lt;span class="p"&gt;():&lt;/span&gt;
  country &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"US"&lt;/span&gt;
  &lt;span class="k"&gt;res&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; request&lt;span class="p"&gt;.&lt;/span&gt;urlopen&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"https://covid2019-api.herokuapp.com/country/%s"&lt;/span&gt; % country&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nb"&gt;string&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;read&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;decode&lt;span class="p"&gt;()&lt;/span&gt;
  info &lt;span class="p"&gt;=&lt;/span&gt; json&lt;span class="p"&gt;.&lt;/span&gt;loads&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;country&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="k"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;vars&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"response"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Country: %s | Confimred:  %i | Deaths: %i | Recovered: %i "&lt;/span&gt; %  &lt;span class="p"&gt;(&lt;/span&gt;country&lt;span class="p"&gt;,&lt;/span&gt; info&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"confirmed"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;  info&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"deaths"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; info&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"recovered"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
getCases&lt;span class="p"&gt;()&lt;/span&gt;
EOF

&lt;span class="k"&gt;endfunction&lt;/span&gt;

&lt;span class="k"&gt;call&lt;/span&gt; CovidUpdate&lt;span class="p"&gt;()&lt;/span&gt;


&lt;span class="c"&gt;" call airline#parts#define_function('foo', "CovidUpdate")&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;g:airline_section_y&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; airline#section#create_right&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="s1"&gt;'ffenc'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; response&lt;span class="p"&gt;])&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;Thanks to &lt;a href="https://github.com/nat236919/Covid2019API"&gt;this&lt;/a&gt; project for providing the API. &lt;/p&gt;

&lt;p&gt;🚨 UPDATE 🚨 &lt;/p&gt;

&lt;p&gt;Threading a bit of python via the vim module is actually really easy!&lt;/p&gt;

&lt;p&gt;Updated version:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight viml"&gt;&lt;code&gt;&lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt; CovidUpdate&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="k"&gt;python3&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&amp;lt;&lt;/span&gt; EOF
from urllib &lt;span class="k"&gt;import&lt;/span&gt; request
&lt;span class="k"&gt;import&lt;/span&gt; threading
&lt;span class="k"&gt;import&lt;/span&gt; json
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="k"&gt;vim&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; getCases&lt;span class="p"&gt;():&lt;/span&gt;
  country &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"US"&lt;/span&gt;
  &lt;span class="k"&gt;res&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; request&lt;span class="p"&gt;.&lt;/span&gt;urlopen&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"https://covid2019-api.herokuapp.com/country/%s"&lt;/span&gt; % country&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nb"&gt;string&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;read&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;decode&lt;span class="p"&gt;()&lt;/span&gt;
  info &lt;span class="p"&gt;=&lt;/span&gt; json&lt;span class="p"&gt;.&lt;/span&gt;loads&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;country&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="k"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;vars&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"airline_section_y"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Country: %s | Confimred:  %i | Deaths: %i | Recovered: %i "&lt;/span&gt; %  &lt;span class="p"&gt;(&lt;/span&gt;country&lt;span class="p"&gt;,&lt;/span&gt; info&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"confirmed"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;  info&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"deaths"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; info&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"recovered"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="k"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;async_call&lt;span class="p"&gt;(&lt;/span&gt;getCases&lt;span class="p"&gt;)&lt;/span&gt;
EOF

&lt;span class="k"&gt;endfunction&lt;/span&gt;

&lt;span class="k"&gt;call&lt;/span&gt; CovidUpdate&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note, the last line in the previous section: &lt;br&gt;
&lt;code&gt;let g:airline_section_y = airline#section#create_right(['ffenc', response])&lt;/code&gt; &lt;br&gt;
is no longer necessary since that variable is set in the Python code. 🧠&lt;/p&gt;

</description>
      <category>vim</category>
      <category>neovim</category>
      <category>python</category>
    </item>
  </channel>
</rss>
