<?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: Peiwen Lu</title>
    <description>The latest articles on DEV Community by Peiwen Lu (@p233).</description>
    <link>https://dev.to/p233</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%2F356190%2Fad215305-ea25-46c8-a0e0-4f995250d863.jpeg</url>
      <title>DEV Community: Peiwen Lu</title>
      <link>https://dev.to/p233</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/p233"/>
    <language>en</language>
    <item>
      <title>Achieving Perfect Vertical Rhythm in Web Browsers</title>
      <dc:creator>Peiwen Lu</dc:creator>
      <pubDate>Sat, 16 Nov 2024 09:41:56 +0000</pubDate>
      <link>https://dev.to/p233/achieving-perfect-vertical-rhythm-in-web-browsers-2d95</link>
      <guid>https://dev.to/p233/achieving-perfect-vertical-rhythm-in-web-browsers-2d95</guid>
      <description>&lt;p&gt;Typography and layout play a crucial role in creating visually appealing and readable web designs. One concept that has always fascinated me is &lt;em&gt;vertical rhythm&lt;/em&gt;, the consistent vertical spacing of text and elements across a web page. Back in 2015, my friend &lt;a href="http://robturlinckx.com/" rel="noopener noreferrer"&gt;Rob Turlinckx&lt;/a&gt; introduced me to this concept, sparking a journey of exploration that led me to develop tools for effectively implementing vertical rhythm in modern web browsers.&lt;/p&gt;

&lt;p&gt;In the early stages of my experimentation, I found some success in aligning headings and paragraphs within isolated sections, such as feature cards. However, maintaining consistent vertical rhythm throughout an entire page proved challenging. My initial attempts relied on visual approximations, tweaking margins and padding until things looked right. This process was both time-consuming and imprecise.&lt;/p&gt;

&lt;p&gt;The turning point came in early 2020 when I discovered the &lt;a href="https://jamonserrano.github.io/plumber-sass/" rel="noopener noreferrer"&gt;Plumber project&lt;/a&gt;. It introduced me to the crucial concept of &lt;em&gt;baseline ratio&lt;/em&gt;, a critical piece of the vertical rhythm puzzle that had previously eluded me. Inspired by Plumber and driven by my long-standing goal of achieving perfect vertical rhythm, I developed &lt;a href="https://github.com/P233/rhythm-sass" rel="noopener noreferrer"&gt;rhythm-sass&lt;/a&gt;. This tool, which powers the typography on this page, enables precise vertical rhythm implementation by utilizing font baseline ratios. While I completed the core functionality shortly after this breakthrough, I only recently finalized the documentation and made it publicly available. As a result, rhythm-sass has been validated through multiple production cases.&lt;/p&gt;

&lt;p&gt;As a web developer, not a professional font designer, I approach baseline ratios primarily from a CSS perspective. Understanding this concept is crucial for effectively utilizing tools like Plumber and rhythm-sass, and for accurately implementing designers' intentions in typography and layout. To grasp the technical foundations, let's examine two key passages from the &lt;a href="https://www.w3.org/TR/CSS21/visudet.html#leading" rel="noopener noreferrer"&gt;CSS 2.1 Specification&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"CSS assumes that every font has font metrics that specify a characteristic height above the baseline and a depth below it. In this section we use A to mean that height (for a given font at a given size) and D the depth. We also define AD = A + D, the distance from the top to the bottom."&lt;/p&gt;

&lt;p&gt;"Still for each glyph, determine the leading L to add, where L = 'line-height' - AD. Half the leading is added above A and the other half below D, giving the glyph and its leading a total height above the baseline of A' = A + L/2 and a total depth of D' = D + L/2."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;From the first specification quote, we learn that &lt;code&gt;A&lt;/code&gt; represents the height of the font above the baseline, &lt;code&gt;D&lt;/code&gt; represents the depth of the font below the baseline, and &lt;code&gt;A + D&lt;/code&gt; equals the font-size. The second quote reveals that the font-size is always centered within the line-height, with the leading (extra space) distributed equally above and below the font. The baseline ratio is the proportion of the font that sits below the baseline relative to the total font size, expressed as &lt;code&gt;D / (A + D)&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Baseline ratio varies significantly across typefaces due to their unique design characteristics and proportions. You can find baseline ratios for popular fonts on &lt;a href="https://jamonserrano.github.io/plumber-sass/baselines/" rel="noopener noreferrer"&gt;Plumber's website&lt;/a&gt;, or use &lt;a href="https://jamonserrano.github.io/plumber-sass/measure/" rel="noopener noreferrer"&gt;its measure tool&lt;/a&gt; to determine the ratio for any specific font.&lt;/p&gt;

&lt;p&gt;With the baseline ratio, font-size, and line-height of a font in hand, we can perform precise calculations to determine the exact distances from the baseline to the top and bottom of the line-height. This level of precision enables us to accurately control the positioning of text elements. Tools like Plumber and rhythm-sass automate these calculations, ensuring consistency across different typefaces and streamlining the implementation of vertical rhythm.&lt;/p&gt;

&lt;p&gt;This precision allows us to create a perfect drop cap, even in the absence of widespread support for the CSS &lt;code&gt;initial-letter&lt;/code&gt; property. With rhythm-sass, you can achieve this effect by setting a sufficiently large font-size and line-height to span two or three rows, applying &lt;code&gt;display: float&lt;/code&gt; to the element, and fine-tuning its position using &lt;code&gt;margin&lt;/code&gt; to align it with the appropriate number of rhythm grids. For detailed usage instructions, please refer to &lt;a href="https://github.com/P233/rhythm-sass" rel="noopener noreferrer"&gt;the rhythm-sass documentation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I hope you like rhythm-sass and find it useful in your projects. I'm always eager to discuss typography and exchange ideas with fellow developers and designers. If you have any questions about rhythm-sass, or if you'd like to share your experiences with web typography, please don't hesitate to reach out. Let's continue to explore the possibilities of beautiful and functional web design together.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>sass</category>
    </item>
    <item>
      <title>Mastering JSX Editing in Emacs with Tree-sitter</title>
      <dc:creator>Peiwen Lu</dc:creator>
      <pubDate>Thu, 16 May 2024 01:14:20 +0000</pubDate>
      <link>https://dev.to/p233/mastering-jsx-editing-in-emacs-with-tree-sitter-2b3a</link>
      <guid>https://dev.to/p233/mastering-jsx-editing-in-emacs-with-tree-sitter-2b3a</guid>
      <description>&lt;p&gt;Emacs 29 introduced built-in support for &lt;a href="https://tree-sitter.github.io/tree-sitter/"&gt;Tree-sitter&lt;/a&gt;, a powerful tool that revolutionizes syntax highlighting and editing. Tree-sitter constructs a concrete syntax tree for source code and efficiently updates it as modifications are made, offering significant improvements in performance and accuracy compared to traditional regular expression parsing.&lt;/p&gt;

&lt;p&gt;While exploring Tree-sitter, I discovered its vast potential for enhancing the editing experience. I started by focusing on the &lt;code&gt;tsx-ts-mode&lt;/code&gt;, which I use most frequently, and created a collection of helpful functions to boost productivity. In this post, I'll share these functions and invite you to contribute your own insights and improvements.&lt;/p&gt;

&lt;p&gt;To better understand Tree-sitter, refer to the &lt;a href="https://www.gnu.org/software/emacs/manual/html_node/elisp/Parsing-Program-Source.html"&gt;Emacs Tree-sitter documentation&lt;/a&gt;. Chinese readers can also check out &lt;a href="https://manateelazycat.github.io/2023/09/02/treesit/"&gt;《TreeSit API 详解》&lt;/a&gt;. Additionally, you can explore the Tree-sitter structure interactively using &lt;code&gt;M-x treesit-explore-mode&lt;/code&gt; and &lt;code&gt;M-x treesit-inspect-mode&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;To help you quickly grasp the essentials, here are some of the most commonly used Tree-sitter APIs covered in this post:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;treesit-node-at&lt;/code&gt;: Get the syntax node at the current point.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;treesit-node-type&lt;/code&gt;: Get the node's type as a string.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;treesit-node-text&lt;/code&gt;: Get the node's text content as a string.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;treesit-parent-until&lt;/code&gt;: Traverse up the tree to find a parent node matching a condition.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;treesit-search-subtree&lt;/code&gt;: Search the node's subtree for a descendant matching a condition.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;treesit-node-child&lt;/code&gt;: Get a node's child at a specific index.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;treesit-node-prev-sibling&lt;/code&gt;: Get the node's previous sibling.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;treesit-node-next-sibling&lt;/code&gt;: Get the node's next sibling.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;treesit-node-start&lt;/code&gt;: Get the node's starting buffer position.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;treesit-node-end&lt;/code&gt;: Get the node's ending buffer position.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now, let's dive into some practical editing functions implemented using Tree-sitter. Keep in mind that all the functions are specific to the &lt;a href="https://github.com/tree-sitter/tree-sitter-typescript"&gt;tree-sitter-typescript&lt;/a&gt; parser and only work in the Emacs 29 built-in &lt;code&gt;tsx-ts-mode&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight common_lisp"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;defun&lt;/span&gt; &lt;span class="nv"&gt;jsx/kill-region-and-goto-start&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;start&lt;/span&gt; &lt;span class="nv"&gt;end&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="s"&gt;"Kill the region between START and END, and move the point to START."&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;kill-region&lt;/span&gt; &lt;span class="nv"&gt;start&lt;/span&gt; &lt;span class="nv"&gt;end&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;goto-char&lt;/span&gt; &lt;span class="nv"&gt;start&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This utility function deletes a specified region and moves the cursor to the start of that region. It serves as a helper function used in other examples.&lt;/p&gt;






&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight common_lisp"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;defun&lt;/span&gt; &lt;span class="nv"&gt;jsx/empty-element&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="s"&gt;"Empty the content of the JSX element containing the point."&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;interactive&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;when-let*&lt;/span&gt; &lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nv"&gt;node&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;treesit-node-at&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;point&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
              &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;element&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;treesit-parent-until&lt;/span&gt; &lt;span class="nv"&gt;node&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;lambda&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                                                    &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="nv"&gt;treesit-node-type&lt;/span&gt; &lt;span class="nv"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="s"&gt;"jsx_element"&lt;/span&gt;&lt;span class="p"&gt;))))&lt;/span&gt;
              &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;opening-node&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;treesit-node-child&lt;/span&gt; &lt;span class="nv"&gt;element&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
              &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;closing-node&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;treesit-node-child&lt;/span&gt; &lt;span class="nv"&gt;element&lt;/span&gt; &lt;span class="mi"&gt;-1&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
              &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;start&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;treesit-node-end&lt;/span&gt; &lt;span class="nv"&gt;opening-node&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
              &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;end&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;treesit-node-start&lt;/span&gt; &lt;span class="nv"&gt;closing-node&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;jsx/kill-region-and-goto-start&lt;/span&gt; &lt;span class="nv"&gt;start&lt;/span&gt; &lt;span class="nv"&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;Inspired by the Vim &lt;code&gt;cit&lt;/code&gt; operation, this function finds the JSX element (tag) enclosing the current point, removes its content while preserving the opening and closing tags.&lt;/p&gt;






&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight common_lisp"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;defun&lt;/span&gt; &lt;span class="nv"&gt;jsx/raise-element&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="s"&gt;"Raise the JSX element containing the point."&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;interactive&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;when-let*&lt;/span&gt; &lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nv"&gt;node&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;treesit-node-at&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;point&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
              &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;element&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;treesit-parent-until&lt;/span&gt; &lt;span class="nv"&gt;node&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;lambda&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                                                    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;member&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;treesit-node-type&lt;/span&gt; &lt;span class="nv"&gt;n&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="s"&gt;"jsx_element"&lt;/span&gt;
                                                              &lt;span class="s"&gt;"jsx_self_closing_element"&lt;/span&gt;&lt;span class="p"&gt;)))))&lt;/span&gt;
              &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;element-text&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;treesit-node-text&lt;/span&gt; &lt;span class="nv"&gt;element&lt;/span&gt; &lt;span class="no"&gt;t&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
              &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;element-parent&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;treesit-parent-until&lt;/span&gt; &lt;span class="nv"&gt;element&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;lambda&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                                                              &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="nv"&gt;treesit-node-type&lt;/span&gt; &lt;span class="nv"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="s"&gt;"jsx_element"&lt;/span&gt;&lt;span class="p"&gt;))))&lt;/span&gt;
              &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;start&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;treesit-node-start&lt;/span&gt; &lt;span class="nv"&gt;element-parent&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
              &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;end&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;treesit-node-end&lt;/span&gt; &lt;span class="nv"&gt;element-parent&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;delete-region&lt;/span&gt; &lt;span class="nv"&gt;start&lt;/span&gt; &lt;span class="nv"&gt;end&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;insert&lt;/span&gt; &lt;span class="nv"&gt;element-text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;indent-region&lt;/span&gt; &lt;span class="nv"&gt;start&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;point&lt;/span&gt;&lt;span class="p"&gt;))))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Drawing inspiration from the &lt;a href="https://github.com/abo-abo/lispy?tab=readme-ov-file#features"&gt;Lispy raises function&lt;/a&gt;, this function moves the current JSX tag one level up in the tree hierarchy and removes the original parent tag.&lt;/p&gt;






&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight common_lisp"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;defun&lt;/span&gt; &lt;span class="nv"&gt;jsx/delete-until&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="s"&gt;"Delete up to the end of the parent closing."&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;interactive&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;when-let*&lt;/span&gt; &lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nv"&gt;node&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;treesit-node-at&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;point&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
              &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;parent&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;treesit-parent-until&lt;/span&gt; &lt;span class="nv"&gt;node&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;lambda&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                                                   &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;member&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;treesit-node-type&lt;/span&gt; &lt;span class="nv"&gt;n&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="s"&gt;"array"&lt;/span&gt;
                                                             &lt;span class="s"&gt;"string"&lt;/span&gt;
                                                             &lt;span class="s"&gt;"arguments"&lt;/span&gt;
                                                             &lt;span class="s"&gt;"named_imports"&lt;/span&gt;
                                                             &lt;span class="s"&gt;"object_pattern"&lt;/span&gt;
                                                             &lt;span class="s"&gt;"formal_parameters"&lt;/span&gt;
                                                             &lt;span class="s"&gt;"jsx_expression"&lt;/span&gt;
                                                             &lt;span class="s"&gt;"jsx_opening_element"&lt;/span&gt;&lt;span class="p"&gt;)))))&lt;/span&gt;
              &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;end&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;1-&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;treesit-node-end&lt;/span&gt; &lt;span class="nv"&gt;parent&lt;/span&gt;&lt;span class="p"&gt;))))&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;delete-region&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;point&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nv"&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;Akin to the Vim &lt;code&gt;ct&lt;/code&gt; command, this function automatically deletes from the current point up to the ending character, such as &lt;code&gt;"&lt;/code&gt;, &lt;code&gt;)&lt;/code&gt;, &lt;code&gt;]&lt;/code&gt;, &lt;code&gt;}&lt;/code&gt;, or &lt;code&gt;&amp;gt;&lt;/code&gt;. Unlike Vim, you don't need to manually specify the matching end character.&lt;/p&gt;






&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight common_lisp"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;defun&lt;/span&gt; &lt;span class="nv"&gt;jsx/kill-attribute-value&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="s"&gt;"Kill the value of the JSX attribute containing the point."&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;interactive&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;when-let*&lt;/span&gt; &lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nv"&gt;node&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;treesit-node-at&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;point&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
              &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;attribute&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;treesit-parent-until&lt;/span&gt; &lt;span class="nv"&gt;node&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;lambda&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                                                      &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="nv"&gt;treesit-node-type&lt;/span&gt; &lt;span class="nv"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="s"&gt;"jsx_attribute"&lt;/span&gt;&lt;span class="p"&gt;))))&lt;/span&gt;
              &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;value&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;treesit-node-child&lt;/span&gt; &lt;span class="nv"&gt;attribute&lt;/span&gt; &lt;span class="mi"&gt;-1&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nv"&gt;start&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;1+&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;treesit-node-start&lt;/span&gt; &lt;span class="nv"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
          &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;end&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;1-&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;treesit-node-end&lt;/span&gt; &lt;span class="nv"&gt;value&lt;/span&gt;&lt;span class="p"&gt;))))&lt;/span&gt;
      &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;jsx/kill-region-and-goto-start&lt;/span&gt; &lt;span class="nv"&gt;start&lt;/span&gt; &lt;span class="nv"&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;This convenient function clears the value of the JSX attribute containing the point.&lt;/p&gt;






&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight common_lisp"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;defun&lt;/span&gt; &lt;span class="nv"&gt;jsx/declaration-to-if-statement&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="s"&gt;"Convert the variable declaration at point to an if statement."&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;interactive&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;when-let*&lt;/span&gt; &lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nv"&gt;node&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;treesit-node-at&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;point&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
              &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;parent&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;treesit-parent-until&lt;/span&gt; &lt;span class="nv"&gt;node&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;lambda&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                                                   &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="nv"&gt;treesit-node-type&lt;/span&gt; &lt;span class="nv"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="s"&gt;"lexical_declaration"&lt;/span&gt;&lt;span class="p"&gt;))))&lt;/span&gt;
              &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;value&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;treesit-search-subtree&lt;/span&gt; &lt;span class="nv"&gt;parent&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;lambda&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                                                      &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="nv"&gt;treesit-node-type&lt;/span&gt; &lt;span class="nv"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="s"&gt;"call_expression"&lt;/span&gt;&lt;span class="p"&gt;))))&lt;/span&gt;
              &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;value-text&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;treesit-node-text&lt;/span&gt; &lt;span class="nv"&gt;value&lt;/span&gt; &lt;span class="no"&gt;t&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
              &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;start&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;treesit-node-start&lt;/span&gt; &lt;span class="nv"&gt;parent&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
              &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;end&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;treesit-node-end&lt;/span&gt; &lt;span class="nv"&gt;parent&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;delete-region&lt;/span&gt; &lt;span class="nv"&gt;start&lt;/span&gt; &lt;span class="nv"&gt;end&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;insert&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;format&lt;/span&gt; &lt;span class="s"&gt;"if (%s) {\n\n}"&lt;/span&gt; &lt;span class="nv"&gt;value-text&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;indent-region&lt;/span&gt; &lt;span class="nv"&gt;start&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;point&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;forward-line&lt;/span&gt; &lt;span class="mi"&gt;-1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;indent-for-tab-command&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Although rarely used, this function can be very handy in specific scenarios. It converts a variable declaration into an if statement, using the variable's value as the condition.&lt;/p&gt;






&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight common_lisp"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;defun&lt;/span&gt; &lt;span class="nv"&gt;jsx/kill-by-node-type&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="s"&gt;"[Experimental] Kill the node or region based on the node type at point."&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;interactive&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;let*&lt;/span&gt; &lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nv"&gt;node&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;treesit-node-at&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;point&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
         &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;node-text&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;treesit-node-text&lt;/span&gt; &lt;span class="nv"&gt;node&lt;/span&gt; &lt;span class="no"&gt;t&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;pcase&lt;/span&gt; &lt;span class="nv"&gt;node-text&lt;/span&gt;
      &lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nb"&gt;or&lt;/span&gt; &lt;span class="s"&gt;"."&lt;/span&gt; &lt;span class="s"&gt;":"&lt;/span&gt; &lt;span class="s"&gt;";"&lt;/span&gt; &lt;span class="s"&gt;"&amp;lt;"&lt;/span&gt; &lt;span class="s"&gt;"&amp;lt;/"&lt;/span&gt; &lt;span class="s"&gt;"&amp;gt;"&lt;/span&gt; &lt;span class="s"&gt;"("&lt;/span&gt; &lt;span class="s"&gt;")"&lt;/span&gt; &lt;span class="s"&gt;"["&lt;/span&gt; &lt;span class="s"&gt;"]"&lt;/span&gt; &lt;span class="s"&gt;"{"&lt;/span&gt; &lt;span class="s"&gt;"}"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
       &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;call-interactively&lt;/span&gt; &lt;span class="ss"&gt;'backward-kill-word&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
      &lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nb"&gt;or&lt;/span&gt; &lt;span class="s"&gt;"'"&lt;/span&gt; &lt;span class="s"&gt;"\""&lt;/span&gt; &lt;span class="s"&gt;"`"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
       &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;let*&lt;/span&gt; &lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nv"&gt;parent-node&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;treesit-node-parent&lt;/span&gt; &lt;span class="nv"&gt;node&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
              &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;start&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;1+&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;treesit-node-start&lt;/span&gt; &lt;span class="nv"&gt;parent-node&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
              &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;end&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;1-&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;treesit-node-end&lt;/span&gt; &lt;span class="nv"&gt;parent-node&lt;/span&gt;&lt;span class="p"&gt;))))&lt;/span&gt;
         &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;jsx/kill-region-and-goto-start&lt;/span&gt; &lt;span class="nv"&gt;start&lt;/span&gt; &lt;span class="nv"&gt;end&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
      &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;","&lt;/span&gt;
       &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;when-let*&lt;/span&gt; &lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nv"&gt;prev-node&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;treesit-node-prev-sibling&lt;/span&gt; &lt;span class="nv"&gt;node&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
                   &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;start&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;treesit-node-start&lt;/span&gt; &lt;span class="nv"&gt;prev-node&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
                   &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;end&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;treesit-node-end&lt;/span&gt; &lt;span class="nv"&gt;node&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
                   &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;space-prefix&lt;/span&gt; &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="nv"&gt;buffer-substring-no-properties&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;1-&lt;/span&gt; &lt;span class="nv"&gt;start&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nv"&gt;start&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="s"&gt;" "&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
         &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;jsx/kill-region-and-goto-start&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nv"&gt;space-prefix&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;1-&lt;/span&gt; &lt;span class="nv"&gt;start&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nv"&gt;start&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nv"&gt;end&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
      &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;_&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;kill-region&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;treesit-node-start&lt;/span&gt; &lt;span class="nv"&gt;node&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;treesit-node-end&lt;/span&gt; &lt;span class="nv"&gt;node&lt;/span&gt;&lt;span class="p"&gt;))))))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This experimental function aggressively deletes the current Tree-sitter node under the point. However, for punctuation characters, it employs &lt;code&gt;backward-kill-word&lt;/code&gt; to maintain consistent deletion behavior.&lt;/p&gt;

&lt;p&gt;Finally, let's assign these functions to some handy keybindings. The example functions presented here are just a fraction of the available functions. Please note that all functions are still under active development. You can find the most up-to-date code in &lt;a href="https://github.com/P233/emacs.d/blob/master/lisp/init-web.el"&gt;my .emacs.d repository&lt;/a&gt;. If you have any ideas for improvement or suggestions, I'd be delighted to hear from you!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight common_lisp"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;add-hook&lt;/span&gt; &lt;span class="ss"&gt;'tsx-ts-mode-hook&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;lambda&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt;
                              &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;define-key&lt;/span&gt; &lt;span class="nv"&gt;tsx-ts-mode-map&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;kbd&lt;/span&gt; &lt;span class="s"&gt;"C-&amp;lt;backspace&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ss"&gt;'jsx/kill-by-node-type&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                              &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;define-key&lt;/span&gt; &lt;span class="nv"&gt;tsx-ts-mode-map&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;kbd&lt;/span&gt; &lt;span class="s"&gt;"C-c C-k"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ss"&gt;'jsx/kill-block&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                              &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;define-key&lt;/span&gt; &lt;span class="nv"&gt;tsx-ts-mode-map&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;kbd&lt;/span&gt; &lt;span class="s"&gt;"C-c C-w"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ss"&gt;'jsx/copy-block&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                              &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;define-key&lt;/span&gt; &lt;span class="nv"&gt;tsx-ts-mode-map&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;kbd&lt;/span&gt; &lt;span class="s"&gt;"C-c C-x"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ss"&gt;'jsx/duplicate-block&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                              &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;define-key&lt;/span&gt; &lt;span class="nv"&gt;tsx-ts-mode-map&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;kbd&lt;/span&gt; &lt;span class="s"&gt;"C-c C-SPC"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ss"&gt;'jsx/select-block&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                              &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;define-key&lt;/span&gt; &lt;span class="nv"&gt;tsx-ts-mode-map&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;kbd&lt;/span&gt; &lt;span class="s"&gt;"C-c C-u"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ss"&gt;'jsx/delete-until&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                              &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;define-key&lt;/span&gt; &lt;span class="nv"&gt;tsx-ts-mode-map&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;kbd&lt;/span&gt; &lt;span class="s"&gt;"C-c C-;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ss"&gt;'jsx/comment-uncomment-block&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                              &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;define-key&lt;/span&gt; &lt;span class="nv"&gt;tsx-ts-mode-map&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;kbd&lt;/span&gt; &lt;span class="s"&gt;"C-c C-t C-e"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ss"&gt;'jsx/empty-element&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                              &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;define-key&lt;/span&gt; &lt;span class="nv"&gt;tsx-ts-mode-map&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;kbd&lt;/span&gt; &lt;span class="s"&gt;"C-c C-t C-r"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ss"&gt;'jsx/raise-element&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                              &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;define-key&lt;/span&gt; &lt;span class="nv"&gt;tsx-ts-mode-map&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;kbd&lt;/span&gt; &lt;span class="s"&gt;"C-c C-t C-p"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ss"&gt;'jsx/move-to-opening-tag&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                              &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;define-key&lt;/span&gt; &lt;span class="nv"&gt;tsx-ts-mode-map&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;kbd&lt;/span&gt; &lt;span class="s"&gt;"C-c C-t C-n"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ss"&gt;'jsx/move-to-closing-tag&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                              &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;define-key&lt;/span&gt; &lt;span class="nv"&gt;tsx-ts-mode-map&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;kbd&lt;/span&gt; &lt;span class="s"&gt;"C-c C-a C-k"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ss"&gt;'jsx/kill-attribute&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                              &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;define-key&lt;/span&gt; &lt;span class="nv"&gt;tsx-ts-mode-map&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;kbd&lt;/span&gt; &lt;span class="s"&gt;"C-c C-a C-w"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ss"&gt;'jsx/copy-attribute&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                              &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;define-key&lt;/span&gt; &lt;span class="nv"&gt;tsx-ts-mode-map&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;kbd&lt;/span&gt; &lt;span class="s"&gt;"C-c C-a C-v"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ss"&gt;'jsx/kill-attribute-value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                              &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;define-key&lt;/span&gt; &lt;span class="nv"&gt;tsx-ts-mode-map&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;kbd&lt;/span&gt; &lt;span class="s"&gt;"C-c C-a C-p"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ss"&gt;'jsx/move-to-prev-attribute&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                              &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;define-key&lt;/span&gt; &lt;span class="nv"&gt;tsx-ts-mode-map&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;kbd&lt;/span&gt; &lt;span class="s"&gt;"C-c C-a C-n"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ss"&gt;'jsx/move-to-next-attribute&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                              &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;define-key&lt;/span&gt; &lt;span class="nv"&gt;tsx-ts-mode-map&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;kbd&lt;/span&gt; &lt;span class="s"&gt;"C-c C-s"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ss"&gt;'my/open-or-create-associated-scss-file&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By leveraging the power of Tree-sitter and these custom functions, you can significantly enhance your TypeScript and JSX editing experience in Emacs. Experiment with these functions, adapt them to your workflow, and share your own innovations with the community. Happy coding!&lt;/p&gt;

</description>
      <category>emacs</category>
      <category>jsx</category>
      <category>treesitter</category>
    </item>
    <item>
      <title>Selectors for Humans, Hashes for Machines</title>
      <dc:creator>Peiwen Lu</dc:creator>
      <pubDate>Fri, 19 Apr 2024 10:19:30 +0000</pubDate>
      <link>https://dev.to/p233/selectors-for-humans-hashes-for-machines-3gdl</link>
      <guid>https://dev.to/p233/selectors-for-humans-hashes-for-machines-3gdl</guid>
      <description>&lt;p&gt;One aspect of &lt;a href="https://github.com/css-modules/css-modules"&gt;CSS modules&lt;/a&gt; that I truly appreciate is its ability to compress class names into very short hashes. This feature allows me to keep my CSS selectors as long and descriptive as needed, while still compressing them into concise three or four character hashes. It aligns with my rule for CSS: &lt;em&gt;selectors should be written for human readability, but compressed for machine efficiency&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;However, setting the hash length too short can lead to hidden hash collision issues which are not easy to detect until you encounter a bug. To address this, I've developed a solution in Vite that utilizes the &lt;code&gt;getJSON&lt;/code&gt; callback function provided by &lt;a href="https://github.com/madyankin/postcss-modules?tab=readme-ov-file#saving-exported-classes"&gt;postcss-modules&lt;/a&gt;. By storing all used selector hashes in a map, we can easily check for any duplicates. If a duplicate hash is detected, an error is immediately raised, and the build process is halted. In such cases, the issue can be resolved by simply increasing the hash length and rebuilding the project.&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="c1"&gt;// vite.config.js&lt;/span&gt;

&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;modulesConfig&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;generateScopedName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;[local]-[hash:base64:4]&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="c1"&gt;// original selectors and four-character hashes in the development environment&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;IS_PROD&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fileSet&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{};&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;hashSet&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{};&lt;/span&gt;
  &lt;span class="nx"&gt;modulesConfig&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;getJSON&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fileSet&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// skip checking files that have already been processed&lt;/span&gt;

      &lt;span class="nx"&gt;fileSet&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;values&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;hashSet&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;CSS MODULES HASH COLLISION ERROR&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nx"&gt;hashSet&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&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="na"&gt;generateScopedName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;[hash:base64:2]&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="c1"&gt;// two-character hashes in the production environment, increase the hash length for needed&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nf"&gt;defineConfig&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;css&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;modules&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;modulesConfig&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I have implemented this code snippet in my &lt;a href="https://github.com/P233/react-template"&gt;react-template&lt;/a&gt;, and I am extremely satisfied with the results. It strikes a perfect balance between readability and efficiency, ensuring that my CSS is both human-friendly and optimized for production.&lt;/p&gt;

</description>
      <category>css</category>
      <category>vite</category>
    </item>
    <item>
      <title>Embedding SVG Icons in CSS</title>
      <dc:creator>Peiwen Lu</dc:creator>
      <pubDate>Mon, 18 Sep 2023 06:06:30 +0000</pubDate>
      <link>https://dev.to/p233/embedding-svg-icons-in-css-31jc</link>
      <guid>https://dev.to/p233/embedding-svg-icons-in-css-31jc</guid>
      <description>&lt;p&gt;I can't quite recall what sparked the idea to embed all SVG icons in CSS instead of importing them as JSX components. Perhaps I was struggling to manage SVG assets for several small projects at the time. Regardless, this exploration delves into embedding SVG icons in CSS.&lt;/p&gt;

&lt;p&gt;We're all aware that &lt;a href="https://css-tricks.com/probably-dont-base64-svg/"&gt;Probably don't Base64 SVG&lt;/a&gt;, but using URL-encoding seems to be a viable alternative. Normally, we utilize the &lt;code&gt;background-image: url(URL_ENCODED_SVG);&lt;/code&gt; format. However, it's challenging to modify the SVG color using this method. &lt;em&gt;Thankfully, the CSS mask feature allows us to transform the SVG into a mask and change its background color, granting us the ability to alter the SVG icon color.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;To demonstrate how this works, let's use the &lt;a href="https://github.com/hypermodules/entypo/blob/master/src/Entypo/home.svg?short_path=63e8a4e"&gt;Entypo home icon&lt;/a&gt; as an example. Here's the SVG source code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;?xml version="1.0" encoding="utf-8"?&amp;gt;
&amp;lt;!-- Generator: Adobe Illustrator 18.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  --&amp;gt;
&amp;lt;!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"&amp;gt;
&amp;lt;svg version="1.1" id="Home" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
     viewBox="0 0 20 20" enable-background="new 0 0 20 20" xml:space="preserve"&amp;gt;
&amp;lt;path d="M18.672,11H17v6c0,0.445-0.194,1-1,1h-4v-6H8v6H4c-0.806,0-1-0.555-1-1v-6H1.328c-0.598,0-0.47-0.324-0.06-0.748L9.292,2.22
    C9.487,2.018,9.743,1.918,10,1.908c0.257,0.01,0.513,0.109,0.708,0.312l8.023,8.031C19.142,10.676,19.27,11,18.672,11z"/&amp;gt;
&amp;lt;/svg&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can convert this icon to the URL-encoded version using the &lt;a href="https://yoksel.github.io/url-encoder/"&gt;URL-encoder for SVG&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nt"&gt;background-image&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nt"&gt;url&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;"data:image/svg+xml,%3C%3Fxml version='1.0' encoding='utf-8'%3F%3E%3C!-- Generator: Adobe Illustrator 18.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) --%3E%3C!DOCTYPE svg PUBLIC '-//W3C//DTD SVG 1.1//EN' 'http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd'%3E%3Csvg version='1.1' id='Home' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' x='0px' y='0px' viewBox='0 0 20 20' enable-background='new 0 0 20 20' xml:space='preserve'%3E%3Cpath d='M18.672,11H17v6c0,0.445-0.194,1-1,1h-4v-6H8v6H4c-0.806,0-1-0.555-1-1v-6H1.328c-0.598,0-0.47-0.324-0.06-0.748L9.292,2.22 C9.487,2.018,9.743,1.918,10,1.908c0.257,0.01,0.513,0.109,0.708,0.312l8.023,8.031C19.142,10.676,19.27,11,18.672,11z'/%3E%3C/svg%3E"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, all we need to do is replace the &lt;code&gt;background-image&lt;/code&gt; property with &lt;code&gt;mask-image&lt;/code&gt; and add &lt;code&gt;background: currentcolor;&lt;/code&gt; to ensure the SVG icon color changes based on its parent's color. This provides an easy way to manage SVG icon colors.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nt"&gt;background&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nt"&gt;currentcolor&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="nt"&gt;mask-image&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nt"&gt;url&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;"URL-encoded SVG"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To make the mask work, we also need to ensure the element is a block element by adding &lt;code&gt;display: block&lt;/code&gt; or other properties that turn an element into a block element. Additionally, we must specify &lt;code&gt;width&lt;/code&gt; and &lt;code&gt;height&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Adding &lt;code&gt;mask-repeat: no-repeat;&lt;/code&gt; and &lt;code&gt;mask-position: center;&lt;/code&gt; (similar to background images) ensures the icon is centered and not repeated as a tile.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.icon-home&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;block&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;24px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;24px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;currentcolor&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="py"&gt;mask-repeat&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;no-repeat&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="py"&gt;mask-position&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;center&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="py"&gt;mask-image&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sx"&gt;url("URL-encoded SVG")&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 code above serves as a basic working example. If we replace &lt;code&gt;background: currentcolor;&lt;/code&gt; with something like &lt;code&gt;background: linear-gradient(...);&lt;/code&gt;, we can create a nice gradient icon, and animate it.&lt;/p&gt;

&lt;p&gt;Creating SVG icons in this manner one by one can be tedious, so I developed a project called &lt;a href="https://peiwen.lu/project/svg-in-css"&gt;SVG-in-CSS&lt;/a&gt; to help manage your SVGs and generate the necessary CSS code. It was inspired by both &lt;a href="https://yoksel.github.io/url-encoder/"&gt;URL-encoder for SVG&lt;/a&gt; and &lt;a href="https://icomoon.io/"&gt;IcoMoon&lt;/a&gt;. You can also manage different projects by downloading the &lt;code&gt;svg-in-css.config.json&lt;/code&gt; file and uploading it to restore your previous project settings. Check out the &lt;a href="https://github.com/P233/svg-in-css"&gt;source code repo&lt;/a&gt; on GitHub, and maybe give it a star if you find it useful.&lt;/p&gt;

&lt;h2&gt;
  
  
  Optimizing SVG with SVGO
&lt;/h2&gt;

&lt;p&gt;I use &lt;a href="https://github.com/svg/svgo"&gt;SVGO&lt;/a&gt; to optimize all SVG assets. As a result, the &lt;a href="https://peiwen.lu/project/svg-in-css"&gt;SVG-in-CSS&lt;/a&gt; project includes a browser version of SVGO with the following configuration settings.&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="nl"&gt;plugins&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;preset-default&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;removeDimensions&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="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;prefixIds&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;params&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;prefix&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;FILE_NAME&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="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;removeDimensions&lt;/code&gt; plugin removes the &lt;code&gt;width&lt;/code&gt; and &lt;code&gt;height&lt;/code&gt; attributes while retaining the &lt;code&gt;viewBox&lt;/code&gt; attribute, ensuring the SVG icon remains scalable. The &lt;code&gt;prefixIds&lt;/code&gt; plugin prevents misuse of SVG filters by adding the file name as a filter prefix.&lt;/p&gt;

&lt;p&gt;After optimization, the SVG icon code would look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nt"&gt;mask-image&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nt"&gt;url&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' xml:space='preserve' viewBox='0 0 20 20'%3E%3Cpath d='M18.672 11H17v6c0 .445-.194 1-1 1h-4v-6H8v6H4c-.806 0-1-.555-1-1v-6H1.328c-.598 0-.47-.324-.06-.748L9.292 2.22c.195-.202.451-.302.708-.312.257.01.513.109.708.312l8.023 8.031c.411.425.539.749-.059.749z'/%3E%3C/svg%3E"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Performance
&lt;/h2&gt;

&lt;p&gt;If you're curious about the performance implications of using SVG icons in this manner, I've created a comparison page at &lt;a href="https://svg-in-css-performance-test.vercel.app"&gt;https://svg-in-css-performance-test.vercel.app&lt;/a&gt; for your consideration. In my opinion, if you have fewer than 100 SVG icons on a single page, the performance impact is minimal and acceptable. However, if you have hundreds of icons, it's best to avoid this method.&lt;/p&gt;

</description>
      <category>svg</category>
      <category>css</category>
      <category>showdev</category>
    </item>
    <item>
      <title>Implement Functional Programming in Sass</title>
      <dc:creator>Peiwen Lu</dc:creator>
      <pubDate>Tue, 11 Jul 2023 17:42:52 +0000</pubDate>
      <link>https://dev.to/p233/implement-functional-programming-in-sass-5gl7</link>
      <guid>https://dev.to/p233/implement-functional-programming-in-sass-5gl7</guid>
      <description>&lt;p&gt;&lt;span&gt;A&lt;/span&gt; few years ago, I started learning the &lt;a href="https://clojurescript.org/"&gt;ClojureScript&lt;/a&gt; language and quickly became fascinated with functional programming. One day, I wondered if it would be possible to implement a similar programming style in Sass, allowing for anonymous functions and &lt;a href="https://clojure.org/guides/threading_macros"&gt;threading macros&lt;/a&gt;. After conducting some experiments, I came up with the following Sass functions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scss"&gt;&lt;code&gt;&lt;span class="nc"&gt;.map-function&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;property&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;inc&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// (2, 3, 4)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.filter-function&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;property&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;odd&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// (1, 3)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.reduce-function&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;property&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;reduce&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;plus&lt;/span&gt; &lt;span class="n"&gt;_1&lt;/span&gt; &lt;span class="n"&gt;_2&lt;/span&gt; &lt;span class="n"&gt;_2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"#"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;"a"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"b"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"c"&lt;/span&gt; &lt;span class="p"&gt;]);&lt;/span&gt; &lt;span class="c1"&gt;// #aabbcc&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.assoc-function&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;property&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;assoc&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt; &lt;span class="c1"&gt;// [1 (a b) 3]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.thread-last-function&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;property&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;thread-last&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;inc&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;plus&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt; &lt;span class="m"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dec&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"math.pow"&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt; &lt;span class="c1"&gt;// 65536&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It turns out to be quite doable. The magic began with the &lt;a href="https://clojure.org/guides/higher_order_functions#_function_literals"&gt;Clojure Function Literal&lt;/a&gt; style anonymous function, &lt;code&gt;#(println %1 %2 %3)&lt;/code&gt;, which can be passed to iterator functions and threading functions. For syntax reasons, I used &lt;code&gt;_&lt;/code&gt; as the placeholder for a single parameter or &lt;code&gt;_1&lt;/code&gt;, &lt;code&gt;_2&lt;/code&gt;, and so on for multiple parameters.&lt;/p&gt;

&lt;p&gt;In this post, I will explain how to accomplish this. Let's take the &lt;code&gt;reduce()&lt;/code&gt; function as an example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scss"&gt;&lt;code&gt;&lt;span class="k"&gt;@use&lt;/span&gt; &lt;span class="s2"&gt;"sass:list"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;@function&lt;/span&gt; &lt;span class="nf"&gt;plus&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$args&lt;/span&gt;&lt;span class="o"&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;// Return the sum of $args&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.reduce-function&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;property&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;reduce&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;plus&lt;/span&gt; &lt;span class="n"&gt;_1&lt;/span&gt; &lt;span class="n"&gt;_2&lt;/span&gt; &lt;span class="n"&gt;_2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"#"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;"a"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"b"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"c"&lt;/span&gt; &lt;span class="p"&gt;]);&lt;/span&gt; &lt;span class="c1"&gt;// #aabbcc&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this case, &lt;code&gt;_1&lt;/code&gt; represents the accumulator, and &lt;code&gt;_2&lt;/code&gt; represents the current value. The function literal is a parentheses list, also known as the &lt;a href="https://en.wikipedia.org/wiki/S-expression"&gt;S-expression&lt;/a&gt;, and the Sass list is fully capable of handling this syntax. Therefore, the first step is to create a caller that accepts a Sass list, takes the first item in the list as the function name, and the rest items as arguments. It would look something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scss"&gt;&lt;code&gt;&lt;span class="k"&gt;@use&lt;/span&gt; &lt;span class="s2"&gt;"sass:meta"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;@function&lt;/span&gt; &lt;span class="nf"&gt;call-fn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$fn&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$args&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;)&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;meta&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;meta&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get-function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$fn&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$args&lt;/span&gt;&lt;span class="o"&gt;...&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;As such, &lt;code&gt;call-fn(plus, 1, 2, 3)&lt;/code&gt; is converted to &lt;code&gt;plus(1, 2, 3)&lt;/code&gt;. The &lt;code&gt;meta.call()&lt;/code&gt; is used to invoke the &lt;code&gt;$fn&lt;/code&gt; with &lt;code&gt;$args&lt;/code&gt;, and the &lt;code&gt;meta.get-function()&lt;/code&gt; ensures that the passed-in function is callable.&lt;/p&gt;

&lt;p&gt;This is just a basic concept. In the actual case, &lt;code&gt;$fn&lt;/code&gt; would be an S-expression, and we need to replace the &lt;code&gt;_&lt;/code&gt; placeholder inside with the values in &lt;code&gt;$args&lt;/code&gt;. So let's update the &lt;code&gt;call-fn()&lt;/code&gt; to a &lt;code&gt;call-lambda()&lt;/code&gt; function that can convert &lt;code&gt;call-lambda((plus, _1, _2), 10, 100)&lt;/code&gt; to &lt;code&gt;plus(10, 100)&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scss"&gt;&lt;code&gt;&lt;span class="k"&gt;@use&lt;/span&gt; &lt;span class="s2"&gt;"sass:list"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;@use&lt;/span&gt; &lt;span class="s2"&gt;"sass:meta"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;@function&lt;/span&gt; &lt;span class="nf"&gt;first&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$list&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Return the first $list&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;@function&lt;/span&gt; &lt;span class="nf"&gt;rest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$list&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Return the rest items in $list&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;@function&lt;/span&gt; &lt;span class="nf"&gt;replace-args&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$args&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$values&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;@for&lt;/span&gt; &lt;span class="nv"&gt;$_i&lt;/span&gt; &lt;span class="ow"&gt;from&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt; &lt;span class="ow"&gt;through&lt;/span&gt; &lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;length&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$values&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;@if&lt;/span&gt; &lt;span class="nv"&gt;$_i&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="nv"&gt;$_index&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;index&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$args&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;index&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$args&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

      &lt;span class="k"&gt;@while&lt;/span&gt; &lt;span class="nv"&gt;$_index&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;null&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$args&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set-nth&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$args&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$_index&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;nth&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$values&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="nv"&gt;$_index&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;index&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$args&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;index&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$args&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_1&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="k"&gt;@else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nv"&gt;$_index&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;index&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$args&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="nv"&gt;$_i&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

      &lt;span class="k"&gt;@while&lt;/span&gt; &lt;span class="nv"&gt;$_index&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;null&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$args&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set-nth&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$args&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$_index&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;nth&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$values&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$_i&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
        &lt;span class="nv"&gt;$_index&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;index&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$args&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="nv"&gt;$_i&lt;/span&gt;&lt;span class="si"&gt;}&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="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;@return&lt;/span&gt; &lt;span class="nv"&gt;$args&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;@function&lt;/span&gt; &lt;span class="nf"&gt;call-lambda&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$lambda&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$args&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nv"&gt;$_fn&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;first&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$lambda&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nv"&gt;$_lambda-args&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;replace-args&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;rest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$lambda&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$args&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;meta&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;meta&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get-function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$_fn&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$_lambda-args&lt;/span&gt;&lt;span class="o"&gt;...&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;In the &lt;code&gt;replace-args()&lt;/code&gt; function, use a &lt;code&gt;@while&lt;/code&gt; loop to support cases where the &lt;code&gt;_&lt;/code&gt; placeholder appears multiple times.&lt;/p&gt;

&lt;p&gt;Here, we have a problem. The &lt;code&gt;meta.get-function()&lt;/code&gt; cannot directly get a Sass module function. For example, &lt;code&gt;meta.get-function("list.index")&lt;/code&gt; is invalid. The correct way would be &lt;code&gt;meta.get-function("index", false, "list")&lt;/code&gt;. So, let's create a new &lt;code&gt;get-function()&lt;/code&gt; function to detect if the passed-in function is a Sass module method, and if so, extract the module name and the method name.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scss"&gt;&lt;code&gt;&lt;span class="k"&gt;@use&lt;/span&gt; &lt;span class="s2"&gt;"sass:meta"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;@use&lt;/span&gt; &lt;span class="s2"&gt;"sass:string"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;@function&lt;/span&gt; &lt;span class="nf"&gt;get-function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$fn&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nv"&gt;$_dot-index&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;index&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$fn&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"."&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;@if&lt;/span&gt; &lt;span class="nv"&gt;$_dot-index&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$_module&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$fn&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$_dot-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="nv"&gt;$_fn&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$fn&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$_dot-index&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="m"&gt;1&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="k"&gt;@return&lt;/span&gt; &lt;span class="n"&gt;meta&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get-function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$_fn&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;false&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$_module&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;@else&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;meta&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get-function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$fn&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We're almost done, there's only one thing left. In iterator functions or threading functions, we can either pass an anonymous function or a named function. We already have the &lt;code&gt;call-fn()&lt;/code&gt; and &lt;code&gt;call-lambda()&lt;/code&gt; functions, so let's add a new &lt;code&gt;auto-call()&lt;/code&gt; function to detect the type of the passed-in function, and correspondingly choose to invoke &lt;code&gt;call-fn()&lt;/code&gt; or &lt;code&gt;call-lambda()&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scss"&gt;&lt;code&gt;&lt;span class="k"&gt;@use&lt;/span&gt; &lt;span class="s2"&gt;"sass:meta"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;@function&lt;/span&gt; &lt;span class="nf"&gt;auto-call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$fn&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$args&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nv"&gt;$_type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;meta&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;type-of&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$fn&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;@if&lt;/span&gt; &lt;span class="nv"&gt;$_type&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;string&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;@return&lt;/span&gt; &lt;span class="nf"&gt;call-fn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$fn&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$args&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;@else&lt;/span&gt; &lt;span class="n"&gt;if&lt;/span&gt; &lt;span class="nv"&gt;$_type&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;list&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;@return&lt;/span&gt; &lt;span class="nf"&gt;call-lambda&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$fn&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$args&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;@else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;@error&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="nv"&gt;$fn&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; is not a function. Please make sure that &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="nv"&gt;$fn&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; is defined as a function before calling it."&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, based on the previous work, implementing the &lt;code&gt;reduce()&lt;/code&gt; function or other functions becomes much simpler. Check the &lt;a href="https://github.com/P233/lambda-sass/blob/master/src/lambda.scss"&gt;source code&lt;/a&gt; for more examples.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scss"&gt;&lt;code&gt;&lt;span class="k"&gt;@function&lt;/span&gt; &lt;span class="nf"&gt;reduce&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$fn&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$init&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$list&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nv"&gt;$_result&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;$init&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;@each&lt;/span&gt; &lt;span class="nv"&gt;$_i&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="nv"&gt;$list&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$_result&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;auto-call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$fn&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$_result&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$_i&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;@return&lt;/span&gt; &lt;span class="nv"&gt;$_result&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;This project has been published as an NPM package named &lt;a href="https://github.com/P233/lambda-sass"&gt;lambda-sass&lt;/a&gt;. The syntax was borrowed from Clojure, but the project name was inspired by the Lisp lambda function. I'd be delighted to see what you create using this library. If you find any functions missing, feel free to inform me or contribute by submitting a pull request.&lt;/p&gt;

</description>
      <category>sass</category>
      <category>clojure</category>
      <category>showdev</category>
    </item>
    <item>
      <title>Emmet Enhancements for Web Development</title>
      <dc:creator>Peiwen Lu</dc:creator>
      <pubDate>Sun, 02 Jul 2023 18:39:55 +0000</pubDate>
      <link>https://dev.to/p233/emmet-enhancements-for-web-development-15op</link>
      <guid>https://dev.to/p233/emmet-enhancements-for-web-development-15op</guid>
      <description>&lt;p&gt;As a front-end developer, &lt;a href="https://emmet.io/"&gt;Emmet&lt;/a&gt; is a tool I rely on daily. I first started using it over a decade ago, back when it was still known as "Zen Coding". This highly efficient tool has been a major timesaver and has significantly enhanced my work experience. Over the years, I've had sporadic ideas on how to improve it, for example, expand &lt;code&gt;m--gutter&lt;/code&gt; to &lt;code&gt;margin: var(--gutter);&lt;/code&gt;. These insights would flash into my mind and I'd jot them down, eventually leading to a strong desire to customize Emmet to my personal tastes.&lt;/p&gt;

&lt;p&gt;My initial attempt at customization was the Sublime Text package &lt;a href="https://packagecontrol.io/packages/Emmet%20Css%20Snippets"&gt;Emmet Css Snippets&lt;/a&gt; that I created 11 years ago. This package is a compilation of 200-300 snippets that adhere to Emmet's abbreviation rules, but with a few personal tweaks such as simplified abbreviations and added pseudo-class abbreviations. At the time, I didn't know any scripting language (including JavaScript), so I manually created each snippet. It was a time-consuming process, but as a side benefit, I now have an excellent recall of CSS properties and values.&lt;/p&gt;

&lt;p&gt;However, I only used Sublime Text for two years before switching to Emacs. I began using the &lt;a href="https://github.com/smihica/emmet-mode"&gt;emmet-mode&lt;/a&gt; and created my own fork (which has since been removed from GitHub). With my limited knowledge of Emacs Lisp, I was only able to modify the snippets in the same way I had done in the Emmet Css Snippets package, and couldn't take it any further.&lt;/p&gt;

&lt;p&gt;About nine months ago, one of my favorite Emacs developers, &lt;a href="https://github.com/manateelazycat"&gt;@manateelazycat&lt;/a&gt;, introduced the &lt;a href="https://github.com/manateelazycat/deno-bridge"&gt;deno-bridge&lt;/a&gt; package. This development allowed us to use &lt;a href="https://deno.com/runtime"&gt;Deno&lt;/a&gt; as the back-end for Emacs plugins. The icing on the cake is that Deno can leverage all NPM packages. This breakthrough finally gave me the opportunity to realize my long-standing ambition. I can now have Emmet process my abbreviations in Emacs, intercept user input before it reaches Emmet, and also alter the content that Emmet returns.&lt;/p&gt;

&lt;p&gt;So I created the &lt;a href="https://github.com/P233/emmet2-mode"&gt;emmet2-mode&lt;/a&gt;, an Emmet-enhanced minor mode for Emacs. I've been using it for over eight months now and it's been performing as expected. It perfectly caters to my personal needs and saves me even more time than Emmet itself. Now, I'm excited to share how I made this possible.&lt;/p&gt;

&lt;h2&gt;
  
  
  Enhancing Markup
&lt;/h2&gt;

&lt;p&gt;First, let's take a look at the markup aspect. While Emmet’s markup abbreviations are expertly designed and I don’t intend to alter them, I have added three additional features:&lt;/p&gt;

&lt;h3&gt;
  
  
  Expanding Abbreviations from Any Position
&lt;/h3&gt;

&lt;p&gt;I find it inconvenient that Emmet only extracts abbreviations backwards. This means that after moving the cursor back to make some changes, I also have to move it back to the end of the edited abbreviation to expand it. Ideally, I would want it to automatically detect the abbreviation, allowing me to expand it from any position. To achieve this, I didn't use the &lt;code&gt;extract&lt;/code&gt; function provided by Emmet. Instead, I created a new extraction function using regex to pinpoint all potential abbreviations in a line, and then selected the correct one based on the current cursor position. Now, when I'm working with the following abbreviation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ul&amp;gt;li*5&amp;gt;h4{title placeholder}+p{content placeholder}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I can expand the abbreviation from any part of it, making content edits a breeze.&lt;/p&gt;

&lt;h3&gt;
  
  
  Support for CSS Modules in JSX
&lt;/h3&gt;

&lt;p&gt;The &lt;a href="https://github.com/css-modules/css-modules"&gt;CSS Modules&lt;/a&gt; is another essential tool that I use daily, probably in all my projects. Therefore, expanding &lt;code&gt;.abc&lt;/code&gt; to &lt;code&gt;&amp;lt;div className={css.abc}&amp;gt;&amp;lt;/div&amp;gt;&lt;/code&gt; is much more practical than expanding to &lt;code&gt;&amp;lt;div class="abc"&amp;gt;&amp;lt;/div&amp;gt;&lt;/code&gt;. The &lt;code&gt;css&lt;/code&gt; here is my CSS Modules object, which can be customized, as I'll explain later.&lt;/p&gt;

&lt;p&gt;At the time of writing this post, Emmet has added this feature in version &lt;code&gt;2.4.5&lt;/code&gt;. However, I would ideally like to expand &lt;code&gt;.a.b.c&lt;/code&gt; to &lt;code&gt;&amp;lt;div className={clsx(css.a, css.b, css.c)}&amp;gt;&amp;lt;/div&amp;gt;&lt;/code&gt;. The &lt;a href="https://github.com/lukeed/clsx"&gt;&lt;code&gt;clsx()&lt;/code&gt;&lt;/a&gt; here is my class names constructor. Currently, my approach may not align with Emmet's.&lt;/p&gt;

&lt;p&gt;Thanks to &lt;a href="https://www.gnu.org/software/emacs/manual/html_node/emacs/Directory-Variables.html"&gt;Emacs Directory Variables&lt;/a&gt;, both the CSS Modules object and the class names constructor can be customized as project-based local variables. Simply create a &lt;code&gt;.dir-locals.el&lt;/code&gt; file at your project's root and add the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight common_lisp"&gt;&lt;code&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nv"&gt;web-mode&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt; &lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nv"&gt;emmet2-css-modules-object&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt; &lt;span class="s"&gt;"style"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
              &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;emmet2-class-names-constructor&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt; &lt;span class="s"&gt;"classnames"&lt;/span&gt;&lt;span class="p"&gt;))))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There is also a &lt;code&gt;(emmet2-markup-variant . "solid")&lt;/code&gt; config to let emmet2-mode work with &lt;a href="https://www.solidjs.com/"&gt;Solid.js&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  CSS Expansion in Markup
&lt;/h3&gt;

&lt;p&gt;Although I rarely use this feature, having the ability to expand CSS in markup is quite handy. This feature was inspired by &lt;a href="https://github.com/smihica/emmet-mode"&gt;emmet-mode&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;When the cursor is inside the &lt;code&gt;&amp;lt;style&amp;gt;|&amp;lt;/style&amp;gt;&lt;/code&gt; tag or &lt;code&gt;&amp;lt;div style="|"&amp;gt;&amp;lt;/div&amp;gt;&lt;/code&gt; attribute, it automatically expands CSS. And, when the cursor is inside the &lt;code&gt;&amp;lt;div style={{|}} /&amp;gt;&lt;/code&gt; JSX attribute, it expands CSS in JS instead.&lt;/p&gt;

&lt;h2&gt;
  
  
  Enhancing CSS
&lt;/h2&gt;

&lt;p&gt;Currently, I primarily use the SCSS syntax, which is a superset to CSS, much like TypeScript is to JavaScript. Hence, the CSS enhancements are essentially SCSS enhancements, and some of them are opinionated.&lt;/p&gt;

&lt;h3&gt;
  
  
  Shorthand Alias
&lt;/h3&gt;

&lt;p&gt;Numeric font-weight shorthands:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;fw2  -&amp;gt;  font-weight: 200;
fw7  -&amp;gt;  font-weight: 700;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Full width and full height shorthands:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;wf  -&amp;gt;  width: 100%;
hf  -&amp;gt;  height: 100%;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I force myself to add &lt;code&gt;z-index&lt;/code&gt; to all &lt;code&gt;absolute&lt;/code&gt; and &lt;code&gt;fixed&lt;/code&gt; positions.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;posa  -&amp;gt;
position: absolute;
z-index: |;

posf1000  -&amp;gt;
position: fixed;
z-index: 1000;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I am planning to completely match CSS properties and values dynamically. Let's see what I can come up with in the future.&lt;/p&gt;

&lt;h3&gt;
  
  
  Personal SCSS Functions
&lt;/h3&gt;

&lt;p&gt;The &lt;a href="https://github.com/modularscale/modularscale-sass"&gt;Modular Scale&lt;/a&gt; &lt;code&gt;ms()&lt;/code&gt; function and the &lt;code&gt;rhythm()&lt;/code&gt; function are commonly used in all my projects.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;t(2)   -&amp;gt;  top: rhythm(2);
fz(1)  -&amp;gt;  font-size: ms(1);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These two abbreviations can significantly enhance my productivity. I'll introduce these in more detail in a future blog post.&lt;/p&gt;

&lt;h3&gt;
  
  
  Custom Properties
&lt;/h3&gt;

&lt;p&gt;CSS custom properties are now widely supported, so it's:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;m--gutter   -&amp;gt;  margin: var(--gutter);
p--a--b--c  -&amp;gt;  padding: var(--a) var(--b) var(--c);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  camelCase Alias
&lt;/h3&gt;

&lt;p&gt;In Emmet, &lt;code&gt;:&lt;/code&gt; and &lt;code&gt;-&lt;/code&gt; are used to separate properties and values, for example, &lt;code&gt;ma&lt;/code&gt; expand to &lt;code&gt;max-width: ;&lt;/code&gt; but &lt;code&gt;m:a&lt;/code&gt; expands to &lt;code&gt;margin: auto;&lt;/code&gt;. I find &lt;code&gt;:&lt;/code&gt; not as easy to type, and it's better to use it as the trigger to expand pseudo-selectors. Therefore, I introduced a camelCase alias. Now, &lt;code&gt;mA&lt;/code&gt; is equivalent to both &lt;code&gt;m:a&lt;/code&gt; and &lt;code&gt;m-a&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ma                -&amp;gt;  max-width: ;
mA == m:a == m-a  -&amp;gt;  margin: auto;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Comma as Abbreviation Splitter
&lt;/h3&gt;

&lt;p&gt;As a &lt;a href="https://en.wikipedia.org/wiki/Dvorak_keyboard_layout"&gt;Dvorak keyboard layout&lt;/a&gt; user, I find the comma much easier to type than &lt;code&gt;+&lt;/code&gt; to join abbreviations.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;t0,r0,b0,l0 == t0+r0+b0+l0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  At Rules
&lt;/h3&gt;

&lt;p&gt;I'm always looking for ways to be more efficient, even if it means typing fewer characters.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@cs  -&amp;gt;  @charset
@kf  -&amp;gt;  @keyframes
@md  -&amp;gt;  @media

@us  -&amp;gt;  @use "|";
@in  -&amp;gt;  @if not | {}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Expanding Pseudo-Classes and Pseudo-Elements
&lt;/h3&gt;

&lt;p&gt;As mentioned earlier, &lt;code&gt;:&lt;/code&gt; is now used as the trigger to expand pseudo-classes or pseudo-elements, starting with the &lt;code&gt;:&lt;/code&gt; symbol, followed by two or three distinct letters.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;:be  -&amp;gt;
&amp;amp;::before {
  |
}

.class:fu  -&amp;gt;
.class::focus {
  |
}

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

&lt;/div&gt;



&lt;p&gt;There's also an easy way to expand functional pseudo-classes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;:n(:fc)  -&amp;gt;
&amp;amp;:not(:first-child) {
  |
}

.class:n(:fc,:lc):be  -&amp;gt;
.class:not(:first-child):not(:last-child)::before {
  |
}

:nc(2n-1)  -&amp;gt;
&amp;amp;:nth-child(2n-1) {
  |
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The pseudo-selectors and CSS at-rules list are borrowed from the &lt;a href="https://github.com/microsoft/vscode-custom-data"&gt;VS Code Custom Data&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Well, that wraps up all the improvements I've implemented for Emmet. For more details, please have a look at the &lt;a href="https://github.com/P233/emmet2-mode"&gt;emmet2-mode&lt;/a&gt; repo. I want to extend my gratitude to the dedicated Emmet team. I managed to accomplish this by building on the hard work they've done.&lt;/p&gt;

</description>
      <category>emmet</category>
      <category>emacs</category>
      <category>deno</category>
      <category>showdev</category>
    </item>
  </channel>
</rss>
