<?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: Marco Bollero</title>
    <description>The latest articles on DEV Community by Marco Bollero (@marco_bollero_ba3c38ddd27).</description>
    <link>https://dev.to/marco_bollero_ba3c38ddd27</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F2733342%2F1987a46d-eac6-4f58-ae6c-7f1e7a4f0e39.jpg</url>
      <title>DEV Community: Marco Bollero</title>
      <link>https://dev.to/marco_bollero_ba3c38ddd27</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/marco_bollero_ba3c38ddd27"/>
    <language>en</language>
    <item>
      <title>I wrote Ratiform to stop writing forms in Ratatui</title>
      <dc:creator>Marco Bollero</dc:creator>
      <pubDate>Fri, 11 Sep 2026 09:19:07 +0000</pubDate>
      <link>https://dev.to/marco_bollero_ba3c38ddd27/i-wrote-ratiform-to-stop-writing-forms-in-ratatui-2be2</link>
      <guid>https://dev.to/marco_bollero_ba3c38ddd27/i-wrote-ratiform-to-stop-writing-forms-in-ratatui-2be2</guid>
      <description>&lt;h2&gt;
  
  
  The problem: two fields are fine, three start to hurt
&lt;/h2&gt;

&lt;p&gt;Anyone who has written even a small TUI with &lt;a href="https://ratatui.rs/" rel="noopener noreferrer"&gt;Ratatui&lt;/a&gt; knows the progression. The first input is trivial: a &lt;code&gt;String&lt;/code&gt; in the app's state, a &lt;code&gt;match&lt;/code&gt; on keyboard events to handle typing and deletion, a &lt;code&gt;Paragraph&lt;/code&gt; widget to draw it. Maybe five minutes of work.&lt;/p&gt;

&lt;p&gt;The second field is basically a copy-paste of the first. It still works, but something starts to creak: now you also need to track &lt;em&gt;which&lt;/em&gt; of the two fields has focus, and &lt;code&gt;Tab&lt;/code&gt; has to move it from one to the other.&lt;/p&gt;

&lt;p&gt;It's with the third field that the problem changes nature. It's no longer "a bit of repeated code" — it's state management that doesn't scale: three &lt;code&gt;String&lt;/code&gt;s synced by hand, an index or an enum for focus, a keyboard whose events need to be routed to the right field based on that index, plus — if you want to do it properly — validation, error messages, a disabled field here, a read-only one there. Every new field adds complexity, and it adds it combinatorially, because it touches focus, validation, and rendering for every other field...&lt;/p&gt;

&lt;p&gt;At that point there are two ways forward: rewrite, for the umpteenth time, the same focus-and-validation infrastructure, or look for a widget that handles it for you.&lt;br&gt;
It's exactly out of this friction that &lt;a href="https://github.com/marc0x71/ratiform" rel="noopener noreferrer"&gt;&lt;code&gt;ratiform&lt;/code&gt;&lt;/a&gt; was born — a crate I wrote to move that infrastructure out of application code.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fuser-attachments%2Fassets%2F8015202a-1613-4621-b599-f46d2f60fa12" class="article-body-image-wrapper"&gt;&lt;img width="1000" height="600" alt="ratiform" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fuser-attachments%2Fassets%2F8015202a-1613-4621-b599-f46d2f60fa12"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  The idea: the field identifier is a real Rust type
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;ratiform&lt;/code&gt; makes one deliberate structural choice: a field's identifier isn't a &lt;code&gt;&amp;amp;str&lt;/code&gt;, it's a generic type &lt;code&gt;T&lt;/code&gt; — in practice, almost always your own &lt;code&gt;enum&lt;/code&gt;, though even an integer works as an identifier!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="nd"&gt;#[derive(Debug,&lt;/span&gt; &lt;span class="nd"&gt;Clone,&lt;/span&gt; &lt;span class="nd"&gt;Copy,&lt;/span&gt; &lt;span class="nd"&gt;PartialEq,&lt;/span&gt; &lt;span class="nd"&gt;Eq,&lt;/span&gt; &lt;span class="nd"&gt;Hash)]&lt;/span&gt;
&lt;span class="k"&gt;enum&lt;/span&gt; &lt;span class="n"&gt;Field&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;Email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;Country&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;Terms&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;FormBuilder&lt;/code&gt;, &lt;code&gt;FormState&amp;lt;T&amp;gt;&lt;/code&gt; and &lt;code&gt;Form&amp;lt;T&amp;gt;&lt;/code&gt; are all generic over this &lt;code&gt;T&lt;/code&gt;. In practice, that means &lt;code&gt;state.value(&amp;amp;Field::Email)&lt;/code&gt; is code the compiler checks for you: rename a variant of the enum, and every place that references it stops compiling until you update it. There's no &lt;code&gt;"email"&lt;/code&gt; string hiding somewhere in the code that can silently drift out of sync with everything else.&lt;/p&gt;

&lt;p&gt;"Typed", here, is about the field's identifier: &lt;code&gt;Field::Email&lt;/code&gt; can never be confused with an arbitrary string. Values themselves remain strings, optionally convertible via &lt;code&gt;value_as&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;With that foundation in place, let's see &lt;code&gt;ratiform&lt;/code&gt; in action — starting from the bare minimum and working up to theming.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. The bare minimum: a single field
&lt;/h2&gt;

&lt;p&gt;First, install it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;cargo add ratiform
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And a form with a single text field:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;ratiform&lt;/span&gt;&lt;span class="p"&gt;::{&lt;/span&gt;&lt;span class="n"&gt;Form&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nn"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;FormBuilder&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="nd"&gt;#[derive(Debug,&lt;/span&gt; &lt;span class="nd"&gt;Hash,&lt;/span&gt; &lt;span class="nd"&gt;Eq,&lt;/span&gt; &lt;span class="nd"&gt;PartialEq)]&lt;/span&gt;
&lt;span class="k"&gt;enum&lt;/span&gt; &lt;span class="n"&gt;Field&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Name&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="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;FormBuilder&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="nf"&gt;.single_line&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Field&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Name"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;.build&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;state&lt;/code&gt; is a &lt;code&gt;FormState&amp;lt;Field&amp;gt;&lt;/code&gt; — the object your application owns for as long as the form is active: no hidden global state, no callback registry. Rendering happens by passing &lt;code&gt;Form::default()&lt;/code&gt; (a stateless &lt;code&gt;StatefulWidget&lt;/code&gt;) and &lt;code&gt;&amp;amp;mut state&lt;/code&gt; to &lt;code&gt;render_stateful_widget&lt;/code&gt;, exactly as you would with a &lt;code&gt;List&lt;/code&gt; or a &lt;code&gt;Table&lt;/code&gt; from Ratatui.&lt;/p&gt;

&lt;p&gt;Worth noting: every field is &lt;strong&gt;required by default&lt;/strong&gt;. You don't need to call &lt;code&gt;.required(...)&lt;/code&gt; to get that behavior — you need &lt;code&gt;.optional()&lt;/code&gt; if you want to opt out, or &lt;code&gt;.required("your custom message")&lt;/code&gt; if you just want to replace the built-in error message with your own.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. More fields, one &lt;code&gt;Tab&lt;/code&gt; to move between them
&lt;/h2&gt;

&lt;p&gt;Adding fields means chaining more calls onto the same builder — this is where the difference from the "three hand-synced &lt;code&gt;String&lt;/code&gt;s" scenario shows up:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="nd"&gt;#[derive(Debug,&lt;/span&gt; &lt;span class="nd"&gt;Hash,&lt;/span&gt; &lt;span class="nd"&gt;Eq,&lt;/span&gt; &lt;span class="nd"&gt;PartialEq)]&lt;/span&gt;
&lt;span class="k"&gt;enum&lt;/span&gt; &lt;span class="n"&gt;Field&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Username&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;Password&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="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;FormBuilder&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="nf"&gt;.single_line&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Field&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Username&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Username"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;.required&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Username is required"&lt;/span&gt;&lt;span class="nf"&gt;.to_owned&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="nf"&gt;.single_line&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Field&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Password&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Password"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;.masked&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="nf"&gt;.required&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Password is required"&lt;/span&gt;&lt;span class="nf"&gt;.to_owned&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="nf"&gt;.build&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Focus, navigation and validation are already handled: &lt;code&gt;Tab&lt;/code&gt;/&lt;code&gt;Shift+Tab&lt;/code&gt; move focus between fields, &lt;code&gt;Ctrl+Enter&lt;/code&gt; (or plain &lt;code&gt;Enter&lt;/code&gt;, if the focused field doesn't intercept it for something else) submits the form — but only if no field is invalid — and &lt;code&gt;Esc&lt;/code&gt; cancels it. The event loop in your application shrinks down to a handful of lines:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nn"&gt;Event&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;Key&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;event&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;read&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;
    &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="py"&gt;.kind&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="nn"&gt;event&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;KeyEventKind&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Press&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="nf"&gt;.handle_input&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;match&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="nf"&gt;.result&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nn"&gt;FormResult&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Submitted&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nn"&gt;FormResult&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Cancelled&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;break&lt;/span&gt; &lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(()),&lt;/span&gt;
        &lt;span class="nn"&gt;FormResult&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Working&lt;/span&gt; &lt;span class="k"&gt;=&amp;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;&lt;code&gt;.masked()&lt;/code&gt; already hints at an important detail: masking is &lt;strong&gt;purely cosmetic&lt;/strong&gt;. A password field shows dots on screen, but validation and &lt;code&gt;value()&lt;/code&gt; still see exactly what the user typed.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Not just text: checkbox, select, text area
&lt;/h2&gt;

&lt;p&gt;A form is rarely made only of single-line inputs. &lt;code&gt;ratiform&lt;/code&gt; covers three other field kinds, with the same chained syntax.&lt;/p&gt;

&lt;p&gt;A &lt;strong&gt;checkbox&lt;/strong&gt; is a boolean, toggled with &lt;code&gt;Space&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="nf"&gt;.checkbox&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Field&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Terms&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"I accept the terms"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;.checked&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;.optional&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A &lt;strong&gt;select&lt;/strong&gt; is a list of &lt;code&gt;(value, label)&lt;/code&gt; pairs, navigated with the arrow keys, &lt;code&gt;Home&lt;/code&gt;/&lt;code&gt;End&lt;/code&gt;, &lt;code&gt;PageUp&lt;/code&gt;/&lt;code&gt;PageDown&lt;/code&gt;. A subtle point: &lt;code&gt;value()&lt;/code&gt; returns the &lt;em&gt;value&lt;/em&gt;, not the label shown on screen:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="nf"&gt;.select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Field&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Country&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Country"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;.values_ref&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="p"&gt;[(&lt;/span&gt;&lt;span class="s"&gt;"IT"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Italy"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"FR"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"France"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"DE"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Germany"&lt;/span&gt;&lt;span class="p"&gt;)])&lt;/span&gt;
    &lt;span class="nf"&gt;.selected&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;.height&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A &lt;strong&gt;text area&lt;/strong&gt; handles multi-line text, with scrolling and paging. There's one keyboard-ergonomics detail worth calling out: since &lt;code&gt;Enter&lt;/code&gt; inserts a newline instead of submitting the form, the combination to confirm while a &lt;code&gt;TextArea&lt;/code&gt; has focus becomes &lt;code&gt;Ctrl+Enter&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="nf"&gt;.text_area&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Field&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Notes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Notes"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;.placeholder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Write here..."&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;.height&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  4. Getting values back: still no magic strings
&lt;/h2&gt;

&lt;p&gt;Once the form has been submitted, &lt;code&gt;values()&lt;/code&gt; consumes the state and returns an iterator of &lt;code&gt;(T, String)&lt;/code&gt; pairs — which you can collect directly into a &lt;code&gt;HashMap&lt;/code&gt; typed on your own enum, as long as that &lt;code&gt;enum&lt;/code&gt; implements &lt;code&gt;Hash&lt;/code&gt; and &lt;code&gt;Eq&lt;/code&gt;, of course:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;values&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;HashMap&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Field&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="nf"&gt;.values&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.collect&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And if you need to read a value while the form is still in progress — say, to reflect what's been typed elsewhere in your UI, like a live preview — you don't have to wait for submission: &lt;code&gt;value(&amp;amp;Field::Email)&lt;/code&gt; and &lt;code&gt;value_as::&amp;lt;u16&amp;gt;(&amp;amp;Field::Port)&lt;/code&gt; — the latter parsing directly into any &lt;code&gt;FromStr&lt;/code&gt; type — both work at any point.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Validation: "required" and "well-formed" are two separate questions
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;ratiform&lt;/code&gt; conceptually separates two different questions: &lt;em&gt;"can this field be empty?"&lt;/em&gt; and &lt;em&gt;"if it isn't empty, does its content have the right shape?"&lt;/em&gt;. The first question is handled by the &lt;code&gt;required&lt;/code&gt;/&lt;code&gt;optional&lt;/code&gt; mechanism above; the second by &lt;code&gt;.validator(...)&lt;/code&gt;, a function &lt;code&gt;Fn(&amp;amp;str) -&amp;gt; Result&amp;lt;(), String&amp;gt;&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="nf"&gt;.single_line&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Field&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;CodiceFiscale&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Codice fiscale"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;.validator&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;ratiform&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;validators&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;max_length&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Too long"&lt;/span&gt;&lt;span class="nf"&gt;.to_owned&lt;/span&gt;&lt;span class="p"&gt;()))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The library already ships a set of common validators under &lt;code&gt;ratiform::validators&lt;/code&gt;: &lt;code&gt;min_length&lt;/code&gt;/&lt;code&gt;max_length&lt;/code&gt; (Unicode-aware), &lt;code&gt;is_numeric&lt;/code&gt;, &lt;code&gt;alphabetic&lt;/code&gt;/&lt;code&gt;alphanumeric&lt;/code&gt;, &lt;code&gt;no_whitespace&lt;/code&gt;, and &lt;code&gt;parsable::&amp;lt;T&amp;gt;&lt;/code&gt;, which relies on &lt;code&gt;T: FromStr&lt;/code&gt; — useful even with types that don't belong to &lt;code&gt;ratiform&lt;/code&gt;, such as &lt;code&gt;parsable::&amp;lt;chrono::NaiveDate&amp;gt;(...)&lt;/code&gt; for a correct, leap-year-aware date validator without &lt;code&gt;ratiform&lt;/code&gt; itself depending on &lt;code&gt;chrono&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;One detail: a validator never sees an empty string. If the field is empty, the required check decides on its own — so none of the built-in validators (or your own) ever needs to special-case an empty string.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. Normalizing, not just validating
&lt;/h2&gt;

&lt;p&gt;Where &lt;code&gt;validator&lt;/code&gt; judges an already-typed value, &lt;code&gt;normalizer&lt;/code&gt; rewrites it into a canonical form &lt;em&gt;before&lt;/em&gt; validation sees it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="nf"&gt;.single_line&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Field&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;CodiceFiscale&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Codice fiscale"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;.normalizer&lt;/span&gt;&lt;span class="p"&gt;(|&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="nf"&gt;.to_uppercase&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="nf"&gt;.validator&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;ratiform&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;validators&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;max_length&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Too long"&lt;/span&gt;&lt;span class="nf"&gt;.to_owned&lt;/span&gt;&lt;span class="p"&gt;()))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The normalizer runs on every keystroke, on &lt;code&gt;set_value&lt;/code&gt;, and on the initial value: the field is never seen — not by the validator, not by &lt;code&gt;is_dirty()&lt;/code&gt;, not by &lt;code&gt;values()&lt;/code&gt; — in any form other than its normalized one. Paired with &lt;code&gt;alphabet(...)&lt;/code&gt; on a single-line field, the split of responsibilities is clean: &lt;code&gt;alphabet&lt;/code&gt; rejects a character outright, &lt;code&gt;normalizer&lt;/code&gt; rewrites one that was allowed in but needs correcting.&lt;/p&gt;

&lt;h2&gt;
  
  
  7. Layout: horizontal or stacked, decided at runtime
&lt;/h2&gt;

&lt;p&gt;By default, every field shows its label and value on the same row (&lt;code&gt;FormLayout::Horizontal&lt;/code&gt;). If the terminal is narrow, &lt;code&gt;FormLayout::Stacked&lt;/code&gt; puts the label above the value instead:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="n"&gt;frame&lt;/span&gt;&lt;span class="nf"&gt;.render_stateful_widget&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nn"&gt;Form&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;default&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.with_layout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;FormLayout&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Stacked&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="n"&gt;area&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;state&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;Since &lt;code&gt;Form&lt;/code&gt; is rebuilt fresh every frame, nothing stops you from picking the layout based on the available width at that moment — which is exactly what &lt;code&gt;examples/layouts.rs&lt;/code&gt; does, switching to &lt;code&gt;Stacked&lt;/code&gt; once the terminal gets too narrow, with no dedicated code needed to intercept the resize.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Horizontal&lt;/code&gt; and &lt;code&gt;Stacked&lt;/code&gt; are enough as long as the form's shape is "one row per field". But a shipping address, say, has a natural geometry of its own: street on its own full row, then city/state/zip split across three columns of different widths. For cases like this there's a third variant, &lt;code&gt;FormLayout::Custom&lt;/code&gt;, which describes the form as an explicit grid of rows and columns, cell by cell:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Email                   Password
_______________________ ____________________

Address
____________________________________________

City                  State          Zip
_____________________ ______________ _______
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each grid cell is a &lt;code&gt;(Constraint, content)&lt;/code&gt; pair: the &lt;code&gt;Constraint&lt;/code&gt; is the same Ratatui type you already use for ordinary layouts (&lt;code&gt;Length&lt;/code&gt;, &lt;code&gt;Fill&lt;/code&gt;, ...), and the content declares &lt;em&gt;what&lt;/em&gt; to draw in that cell — a field's label (&lt;code&gt;Label&lt;/code&gt;), its input widget (&lt;code&gt;Value&lt;/code&gt;), its validation message (&lt;code&gt;Error&lt;/code&gt;) — or nothing at all, for a spacer. The most readable way to write it is the &lt;code&gt;custom_layout!&lt;/code&gt; macro, which mirrors the grid row by row:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;ratiform&lt;/span&gt;&lt;span class="p"&gt;::{&lt;/span&gt;&lt;span class="n"&gt;Form&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;FormLayout&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nn"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;FormBuilder&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;custom_layout&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;grid_layout&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nd"&gt;custom_layout!&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Email | Password&lt;/span&gt;
    &lt;span class="n"&gt;row&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Constraint&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;Fill&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nf"&gt;Label&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Field&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Email&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Constraint&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;Fill&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nf"&gt;Label&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Field&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Password&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="n"&gt;row&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Constraint&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;Fill&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nf"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Field&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Email&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Constraint&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;Fill&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nf"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Field&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Password&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="n"&gt;row&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Constraint&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;Length&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nf"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Field&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Email&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Constraint&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;Fill&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nf"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Field&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Password&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;

    &lt;span class="c1"&gt;// Address&lt;/span&gt;
    &lt;span class="n"&gt;row&lt;/span&gt; &lt;span class="p"&gt;[(&lt;/span&gt;&lt;span class="nn"&gt;Constraint&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;Fill&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nf"&gt;Label&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Field&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Address&lt;/span&gt;&lt;span class="p"&gt;))],&lt;/span&gt;
    &lt;span class="n"&gt;row&lt;/span&gt; &lt;span class="p"&gt;[(&lt;/span&gt;&lt;span class="nn"&gt;Constraint&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;Fill&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nf"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Field&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Address&lt;/span&gt;&lt;span class="p"&gt;))],&lt;/span&gt;
    &lt;span class="n"&gt;row&lt;/span&gt; &lt;span class="p"&gt;[(&lt;/span&gt;&lt;span class="nn"&gt;Constraint&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;Fill&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nf"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Field&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Address&lt;/span&gt;&lt;span class="p"&gt;))],&lt;/span&gt;

    &lt;span class="c1"&gt;// City | State | Zip&lt;/span&gt;
    &lt;span class="n"&gt;row&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Constraint&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;Fill&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nf"&gt;Label&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Field&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;City&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Constraint&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;Fill&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nf"&gt;Label&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Field&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;State&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Constraint&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;Length&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nf"&gt;Label&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Field&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Zip&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="n"&gt;row&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Constraint&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;Fill&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nf"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Field&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;City&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Constraint&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;Fill&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nf"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Field&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;State&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Constraint&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;Length&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nf"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Field&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Zip&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="n"&gt;row&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Constraint&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;Fill&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nf"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Field&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;City&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Constraint&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;Fill&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nf"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Field&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;State&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Constraint&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;Length&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nf"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Field&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Zip&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;let&lt;/span&gt; &lt;span class="n"&gt;form&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Form&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;default&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.with_layout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;FormLayout&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;Custom&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;grid_layout&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Three things worth noting:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Label, value, and error are independent cells.&lt;/strong&gt; This isn't a cosmetic detail: you can place &lt;code&gt;Email&lt;/code&gt;'s label above its value, yet aligned on the same row as &lt;code&gt;Password&lt;/code&gt;'s label — something no combination of &lt;code&gt;Horizontal&lt;/code&gt;/&lt;code&gt;Stacked&lt;/code&gt; allows, since there the three parts of a field always stay a single block.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A spacer is a cell with &lt;code&gt;None&lt;/code&gt; content&lt;/strong&gt; instead of one of the three identifiers — handy for visually separating groups of fields without inventing a dummy field.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Focus still follows the order fields were declared in the builder, not their order on the grid.&lt;/strong&gt; If the grid mirrors the &lt;code&gt;Email → Password → Address → ...&lt;/code&gt; sequence used in &lt;code&gt;single_line(...)&lt;/code&gt;, &lt;code&gt;Tab&lt;/code&gt; moves in the "natural" order you'd expect looking at the screen; if the two sequences diverge, &lt;code&gt;Tab&lt;/code&gt; still works, but jumps from one point on screen to another in an order the eye doesn't anticipate. The reverse also holds: a field left out of the grid still receives focus when its turn comes — just with no visible cursor, and nowhere to show a validation error.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you'd rather assemble the grid programmatically — rows generated in a loop, for instance — &lt;code&gt;CustomLayout::builder()&lt;/code&gt; is the fluent equivalent of the same macro:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;grid_layout&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;CustomLayout&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="nf"&gt;.row&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="nf"&gt;.label&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Constraint&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;Fill&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nn"&gt;Field&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Email&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;.label&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Constraint&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;Fill&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nn"&gt;Field&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Password&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;.row&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="nf"&gt;.value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Constraint&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;Fill&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nn"&gt;Field&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Email&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;.value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Constraint&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;Fill&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nn"&gt;Field&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Password&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;.build&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, &lt;code&gt;.with_column_gap(n)&lt;/code&gt; on &lt;code&gt;CustomLayout&lt;/code&gt; sets the horizontal gap between adjacent columns in the same row (1 by default) — the first column of every row is naturally never preceded by any spacing.&lt;/p&gt;

&lt;h2&gt;
  
  
  8. Theming: when the default gray isn't enough
&lt;/h2&gt;

&lt;p&gt;By default, &lt;code&gt;Form::default()&lt;/code&gt; renders with a gray/bold/reversed scheme. To customize it, you build a &lt;code&gt;FormStyle&lt;/code&gt; and pass it to &lt;code&gt;Form::with_style(...)&lt;/code&gt; — nothing surprising so far. What makes the difference is &lt;em&gt;how&lt;/em&gt; you describe that &lt;code&gt;FormStyle&lt;/code&gt;: a small rule engine, where each rule declares &lt;em&gt;who&lt;/em&gt; it applies to, across three independent axes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;Widgets&lt;/code&gt;&lt;/strong&gt; — which kind of field: &lt;code&gt;SINGLE_LINE&lt;/code&gt;, &lt;code&gt;TEXT_AREA&lt;/code&gt;, &lt;code&gt;CHECK_BOX&lt;/code&gt;, &lt;code&gt;SELECT&lt;/code&gt;, &lt;code&gt;MULTI_SELECT&lt;/code&gt;, or &lt;code&gt;ANY&lt;/code&gt; for all of them.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;Parts&lt;/code&gt;&lt;/strong&gt; — which visual part of that field: &lt;code&gt;LABEL&lt;/code&gt; (the caption), &lt;code&gt;AREA&lt;/code&gt; (the box's background), &lt;code&gt;TEXT&lt;/code&gt; (the typed text), &lt;code&gt;PLACEHOLDER&lt;/code&gt;, &lt;code&gt;MARKER&lt;/code&gt; (a checkbox's &lt;code&gt;[x]&lt;/code&gt; glyph, or a multi-select's marker), &lt;code&gt;ITEM&lt;/code&gt;/&lt;code&gt;ACTIVE&lt;/code&gt;/&lt;code&gt;SELECTED&lt;/code&gt; (a select's rows, and which of them has the cursor or is chosen), &lt;code&gt;ERROR&lt;/code&gt;, or &lt;code&gt;ANY&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;States&lt;/code&gt;&lt;/strong&gt; — the field's current state: &lt;code&gt;NORMAL&lt;/code&gt;, &lt;code&gt;FOCUSED&lt;/code&gt;, &lt;code&gt;DISABLED&lt;/code&gt;, &lt;code&gt;READ_ONLY&lt;/code&gt;, or &lt;code&gt;ANY&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each of the three is a bitmask combined with &lt;code&gt;|&lt;/code&gt; — &lt;code&gt;Widgets::SINGLE_LINE | Widgets::TEXT_AREA&lt;/code&gt; is just as valid a rule as a single constant. A rule is written with &lt;code&gt;FormStyleBuilder::add(widgets, parts, states, style)&lt;/code&gt;, and you declare as many as you need:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;ratatui&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;style&lt;/span&gt;&lt;span class="p"&gt;::{&lt;/span&gt;&lt;span class="n"&gt;Color&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Style&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;ratiform&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;style&lt;/span&gt;&lt;span class="p"&gt;::{&lt;/span&gt;&lt;span class="n"&gt;FormStyle&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Parts&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;States&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Widgets&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;label&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Style&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;default&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.fg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Color&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Cyan&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Style&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;default&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.fg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Color&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;White&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;my_style&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;FormStyle&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="nf"&gt;.add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Widgets&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;ANY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nn"&gt;Parts&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;LABEL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nn"&gt;States&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;NORMAL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;label&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;.add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Widgets&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;ANY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nn"&gt;Parts&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;LABEL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nn"&gt;States&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;FOCUSED&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;label&lt;/span&gt;&lt;span class="nf"&gt;.bold&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="nf"&gt;.add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nn"&gt;Widgets&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;ANY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nn"&gt;Parts&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;TEXT&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nn"&gt;Parts&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;ITEM&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nn"&gt;Parts&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;MARKER&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nn"&gt;States&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;NORMAL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;.add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nn"&gt;Widgets&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;ANY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nn"&gt;Parts&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;TEXT&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nn"&gt;Parts&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;ITEM&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nn"&gt;Parts&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;MARKER&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nn"&gt;States&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;FOCUSED&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="nf"&gt;.bold&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;.add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nn"&gt;Widgets&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;ANY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nn"&gt;Parts&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;AREA&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nn"&gt;Parts&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;ACTIVE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nn"&gt;States&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;FOCUSED&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="nf"&gt;.bg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Color&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Blue&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;.add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nn"&gt;Widgets&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;ANY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nn"&gt;Parts&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;ERROR&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nn"&gt;States&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;ANY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nn"&gt;Style&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;default&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.bg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Color&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Red&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;.fg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Color&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;White&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;.bold&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;.build&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="n"&gt;frame&lt;/span&gt;&lt;span class="nf"&gt;.render_stateful_widget&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Form&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;default&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.with_style&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;my_style&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;area&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This example (taken from &lt;code&gt;examples/theming.rs&lt;/code&gt;) shows two concrete advantages over five fixed slots: &lt;code&gt;TEXT&lt;/code&gt;, &lt;code&gt;ITEM&lt;/code&gt; and &lt;code&gt;MARKER&lt;/code&gt; — that is, "the actual content", whether it's typed text, a select's row, or a checkbox's marker — share the same rule in one shot, instead of being three separate properties you'd have to keep in sync by hand; and &lt;code&gt;AREA | ACTIVE&lt;/code&gt; does the same for highlighting, whether that's a focused &lt;code&gt;SingleLine&lt;/code&gt;'s background or a &lt;code&gt;Select&lt;/code&gt;'s active row.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Rules can be declared in any order.&lt;/strong&gt; &lt;code&gt;FormStyleBuilder::build()&lt;/code&gt; sorts them by specificity on its own before resolving any overlaps: a rule naming a single widget beats one naming all five with &lt;code&gt;ANY&lt;/code&gt;, even if the latter was written afterward; the same cascades through &lt;code&gt;Parts&lt;/code&gt; and then &lt;code&gt;States&lt;/code&gt;. Declaration order only matters as the final tie-break, when two rules are equally specific — in that case the last one written wins. In practice: you can start with a broad rule (&lt;code&gt;Widgets::ANY, Parts::ANY, States::ANY, normal&lt;/code&gt;) as the baseline for the whole form, then refine it with progressively more targeted rules, without worrying about which line comes first in the code.&lt;/p&gt;

&lt;p&gt;The default theme itself is built with the exact same mechanism — it isn't a special case, just a &lt;code&gt;FormStyle::builder()&lt;/code&gt; with a particular set of rules already written for you: a dark background for the &lt;code&gt;AREA&lt;/code&gt; of &lt;code&gt;SingleLine&lt;/code&gt;/&lt;code&gt;TextArea&lt;/code&gt;, bold for the label and content when a field has focus, reversed colors for a select's active row, red and bold for errors, italic gray for placeholders, and a uniform strikethrough — across every part, with a single &lt;code&gt;Parts::ANY&lt;/code&gt; rule — for disabled fields.&lt;/p&gt;

&lt;h2&gt;
  
  
  Closing the loop
&lt;/h2&gt;

&lt;p&gt;The thread running through everything, from the first field to full theming, stays the same: &lt;code&gt;ratiform&lt;/code&gt; owns input, focus, validation and navigation — exactly the part that becomes painful to write by hand past the second field — but it never owns your data model. The identifier stays your own type from beginning to end, the value always comes back as a &lt;code&gt;String&lt;/code&gt; tied to that identifier, and no step in between forces you to invent an interchange format for data the compiler already knew about from the start.&lt;/p&gt;

&lt;p&gt;Having said what it does, it's worth being just as clear about what &lt;code&gt;ratiform&lt;/code&gt; doesn't do:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;it isn't an application framework: it owns focus, input and validation for individual fields, not domain logic, screen routing, or data persistence;&lt;/li&gt;
&lt;li&gt;it doesn't manage the event loop: you're the one reading events from &lt;code&gt;crossterm&lt;/code&gt; and passing each &lt;code&gt;KeyEvent&lt;/code&gt; to &lt;code&gt;handle_input(...)&lt;/code&gt;;&lt;/li&gt;
&lt;li&gt;it doesn't automatically turn the form into your own &lt;code&gt;struct&lt;/code&gt;: &lt;code&gt;values()&lt;/code&gt; returns &lt;code&gt;(T, String)&lt;/code&gt; pairs, and mapping them to a typed struct is left to you;&lt;/li&gt;
&lt;li&gt;it doesn't handle the mouse: &lt;code&gt;handle_input&lt;/code&gt; only accepts keyboard events.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;ratiform&lt;/code&gt; is still at version 0.x: its public API can therefore still evolve, even though the core ideas — typed identifiers, the builder/state/widget split, validation and normalization — are by now fairly settled.&lt;/p&gt;

&lt;p&gt;The code, the full examples, and the changelog are on the &lt;a href="https://github.com/marc0x71/ratiform" rel="noopener noreferrer"&gt;GitHub repository&lt;/a&gt;; the crate is published on &lt;a href="https://crates.io/crates/ratiform" rel="noopener noreferrer"&gt;crates.io&lt;/a&gt;.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;This article was originally written in Italian and translated into English with the help of AI.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>rust</category>
      <category>ratatui</category>
    </item>
    <item>
      <title>Ho scritto Ratiform per smettere di scrivere i form in Ratatui</title>
      <dc:creator>Marco Bollero</dc:creator>
      <pubDate>Fri, 11 Sep 2026 09:06:37 +0000</pubDate>
      <link>https://dev.to/marco_bollero_ba3c38ddd27/ho-scritto-ratiform-per-smettere-di-scrivere-i-form-in-ratatui-28ep</link>
      <guid>https://dev.to/marco_bollero_ba3c38ddd27/ho-scritto-ratiform-per-smettere-di-scrivere-i-form-in-ratatui-28ep</guid>
      <description>&lt;h2&gt;
  
  
  Il problema: due campi vanno bene, tre iniziano a far male
&lt;/h2&gt;

&lt;p&gt;Chi ha scritto anche solo una TUI con &lt;a href="https://ratatui.rs/" rel="noopener noreferrer"&gt;Ratatui&lt;/a&gt; conosce la progressione. Il primo input è banale: uno &lt;code&gt;String&lt;/code&gt; nello stato dell'app, un &lt;code&gt;match&lt;/code&gt; sugli eventi tastiera per gestire inserimento e cancellazione, un widget &lt;code&gt;Paragraph&lt;/code&gt; per disegnarlo. Forse solo cinque minuti di lavoro.&lt;/p&gt;

&lt;p&gt;Il secondo campo si scrive praticamente per copia-incolla del primo. Funziona ancora, ma qualcosa inizia a scricchiolare: ora serve anche capire &lt;em&gt;quale&lt;/em&gt; dei due campi ha il focus, e &lt;code&gt;Tab&lt;/code&gt; deve spostarlo dall'uno all'altro.&lt;/p&gt;

&lt;p&gt;È con il terzo campo che il problema cambia natura. Non è più "un po' di codice ripetuto", è gestione dello stato che non scala: tre pezzi di &lt;code&gt;String&lt;/code&gt; sincronizzati a mano, un indice o un enum per il focus, una tastiera i cui eventi vanno smistati al campo giusto in base a quell'indice, più — se vuoi fare le cose per bene — validazione, messaggi di errore, un campo disabilitato qui e uno in sola lettura là. Ogni nuovo campo aggiunge complessità e la aggiunge in modo combinatorio, perché tocca il focus, la validazione e il rendering di tutti gli altri...&lt;/p&gt;

&lt;p&gt;A questo punto le strade sono due: scrivere daccapo, per l'ennesima volta, la stessa infrastruttura di gestione-focus-e-validazione, oppure cercare un widget che se ne occupi al posto tuo.&lt;br&gt;
È proprio da questa frizione che è nato &lt;a href="https://github.com/marc0x71/ratiform" rel="noopener noreferrer"&gt;&lt;code&gt;ratiform&lt;/code&gt;&lt;/a&gt;, una crate che ho scritto per spostare questa infrastruttura fuori dal codice dell'applicazione.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fuser-attachments%2Fassets%2F8015202a-1613-4621-b599-f46d2f60fa12" class="article-body-image-wrapper"&gt;&lt;img width="1000" height="600" alt="ratiform" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fuser-attachments%2Fassets%2F8015202a-1613-4621-b599-f46d2f60fa12"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  L'idea: l'identificatore del campo è un tipo Rust vero
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;ratiform&lt;/code&gt; fa una scelta strutturale precisa: l'identificatore di un campo non è un &lt;code&gt;&amp;amp;str&lt;/code&gt;, è un tipo generico &lt;code&gt;T&lt;/code&gt; — nella pratica, quasi sempre un tuo &lt;code&gt;enum&lt;/code&gt;, ma  anche un intero può essere usato come identificatore!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="nd"&gt;#[derive(Debug,&lt;/span&gt; &lt;span class="nd"&gt;Clone,&lt;/span&gt; &lt;span class="nd"&gt;Copy,&lt;/span&gt; &lt;span class="nd"&gt;PartialEq,&lt;/span&gt; &lt;span class="nd"&gt;Eq,&lt;/span&gt; &lt;span class="nd"&gt;Hash)]&lt;/span&gt;
&lt;span class="k"&gt;enum&lt;/span&gt; &lt;span class="n"&gt;Field&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;Email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;Country&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;Terms&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;FormBuilder&lt;/code&gt;, &lt;code&gt;FormState&amp;lt;T&amp;gt;&lt;/code&gt; e &lt;code&gt;Form&amp;lt;T&amp;gt;&lt;/code&gt; sono tutti generici su questo &lt;code&gt;T&lt;/code&gt;. Il risultato pratico è che &lt;code&gt;state.value(&amp;amp;Field::Email)&lt;/code&gt; è codice che il compilatore controlla per te: se rinomini una variante dell'enum, ogni punto che la referenzia smette di compilare finché non lo aggiorni. Non c'è nessuna stringa "email" nascosta in un punto qualunque del codice che può disallinearsi dal resto senza produrre un errore di compilazione.&lt;/p&gt;

&lt;p&gt;“Tipizzato”, qui, riguarda l'identificatore del campo: &lt;code&gt;Field::Email&lt;/code&gt; non può essere confuso con una stringa arbitraria. I valori rimangono invece stringhe, eventualmente convertibili tramite &lt;code&gt;value_as&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Con questa base, vediamo &lt;code&gt;ratiform&lt;/code&gt; in azione, partendo dal minimo indispensabile e arrivando fino al theming.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Il minimo indispensabile: un solo campo
&lt;/h2&gt;

&lt;p&gt;Prima di tutto, l'installazione:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;cargo add ratiform
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;E un form con un solo campo di testo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;ratiform&lt;/span&gt;&lt;span class="p"&gt;::{&lt;/span&gt;&lt;span class="n"&gt;Form&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nn"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;FormBuilder&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="nd"&gt;#[derive(Debug,&lt;/span&gt; &lt;span class="nd"&gt;Hash,&lt;/span&gt; &lt;span class="nd"&gt;Eq,&lt;/span&gt; &lt;span class="nd"&gt;PartialEq)]&lt;/span&gt;
&lt;span class="k"&gt;enum&lt;/span&gt; &lt;span class="n"&gt;Field&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Name&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="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;FormBuilder&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="nf"&gt;.single_line&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Field&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Name"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;.build&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;state&lt;/code&gt; è un &lt;code&gt;FormState&amp;lt;Field&amp;gt;&lt;/code&gt; — l'oggetto che la tua applicazione possiede per tutta la vita del form: niente stato globale nascosto, niente registro di callback. Il rendering avviene passando &lt;code&gt;Form::default()&lt;/code&gt; (uno &lt;code&gt;StatefulWidget&lt;/code&gt; stateless) e &lt;code&gt;&amp;amp;mut state&lt;/code&gt; a &lt;code&gt;render_stateful_widget&lt;/code&gt;, esattamente come faresti con una &lt;code&gt;List&lt;/code&gt; o una &lt;code&gt;Table&lt;/code&gt; di Ratatui.&lt;/p&gt;

&lt;p&gt;Da notare: ogni campo è &lt;strong&gt;obbligatorio di default&lt;/strong&gt;. Non serve chiamare &lt;code&gt;.required(...)&lt;/code&gt; per ottenere questo comportamento — serve semmai &lt;code&gt;.optional()&lt;/code&gt; per disattivarlo, o &lt;code&gt;.required("messaggio personalizzato")&lt;/code&gt; se vuoi sostituire il messaggio d'errore predefinito con uno tuo.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Più campi, un solo &lt;code&gt;Tab&lt;/code&gt; per spostarsi
&lt;/h2&gt;

&lt;p&gt;Aggiungere campi significa incatenare altre chiamate sullo stesso builder — è qui che si vede la differenza rispetto allo scenario "tre &lt;code&gt;String&lt;/code&gt; sincronizzate a mano":&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="nd"&gt;#[derive(Debug,&lt;/span&gt; &lt;span class="nd"&gt;Hash,&lt;/span&gt; &lt;span class="nd"&gt;Eq,&lt;/span&gt; &lt;span class="nd"&gt;PartialEq)]&lt;/span&gt;
&lt;span class="k"&gt;enum&lt;/span&gt; &lt;span class="n"&gt;Field&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Username&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;Password&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="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;FormBuilder&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="nf"&gt;.single_line&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Field&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Username&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Username"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;.required&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Username is required"&lt;/span&gt;&lt;span class="nf"&gt;.to_owned&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="nf"&gt;.single_line&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Field&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Password&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Password"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;.masked&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="nf"&gt;.required&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Password is required"&lt;/span&gt;&lt;span class="nf"&gt;.to_owned&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="nf"&gt;.build&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Focus, navigazione e validazione sono già gestiti: &lt;code&gt;Tab&lt;/code&gt;/&lt;code&gt;Shift+Tab&lt;/code&gt; spostano il focus tra i campi, &lt;code&gt;Ctrl+Enter&lt;/code&gt; (o semplicemente &lt;code&gt;Enter&lt;/code&gt;, se il campo attivo non lo intercetta per un altro scopo) invia il form — ma solo se nessun campo è invalido — ed &lt;code&gt;Esc&lt;/code&gt; lo annulla. Il ciclo di eventi nella tua applicazione si riduce a una manciata di righe:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nn"&gt;Event&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;Key&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;event&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;read&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;
    &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="py"&gt;.kind&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="nn"&gt;event&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;KeyEventKind&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Press&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="nf"&gt;.handle_input&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;match&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="nf"&gt;.result&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nn"&gt;FormResult&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Submitted&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nn"&gt;FormResult&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Cancelled&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;break&lt;/span&gt; &lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(()),&lt;/span&gt;
        &lt;span class="nn"&gt;FormResult&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Working&lt;/span&gt; &lt;span class="k"&gt;=&amp;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;Da &lt;code&gt;.masked()&lt;/code&gt; si intuisce già un dettaglio importante: il mascheramento è &lt;strong&gt;solo cosmetico&lt;/strong&gt;. Un campo password mostra puntini a schermo, ma validazione e &lt;code&gt;value()&lt;/code&gt; continuano a vedere quello che l'utente ha effettivamente digitato.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Non solo testo: checkbox, select, area di testo
&lt;/h2&gt;

&lt;p&gt;Un form raramente è fatto solo di input a riga singola. &lt;code&gt;ratiform&lt;/code&gt; copre altri tre tipi di campo, con la stessa sintassi a catena.&lt;/p&gt;

&lt;p&gt;Una &lt;strong&gt;checkbox&lt;/strong&gt; è un booleano, attivato con &lt;code&gt;Space&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="nf"&gt;.checkbox&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Field&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Terms&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"I accept the terms"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;.checked&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;.optional&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Una &lt;strong&gt;select&lt;/strong&gt; è una lista di coppie &lt;code&gt;(valore, etichetta)&lt;/code&gt;, navigabile con le frecce, &lt;code&gt;Home&lt;/code&gt;/&lt;code&gt;End&lt;/code&gt;, &lt;code&gt;PageUp&lt;/code&gt;/&lt;code&gt;PageDown&lt;/code&gt;. Punto sottile: &lt;code&gt;value()&lt;/code&gt; restituisce il &lt;em&gt;valore&lt;/em&gt;, non l'etichetta visualizzata:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="nf"&gt;.select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Field&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Country&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Country"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;.values_ref&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="p"&gt;[(&lt;/span&gt;&lt;span class="s"&gt;"IT"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Italy"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"FR"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"France"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"DE"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Germany"&lt;/span&gt;&lt;span class="p"&gt;)])&lt;/span&gt;
    &lt;span class="nf"&gt;.selected&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;.height&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Una &lt;strong&gt;text area&lt;/strong&gt; gestisce testo multilinea, con scrolling e paginazione. Qui c'è un dettaglio di ergonomia della tastiera che vale la pena notare: dato che &lt;code&gt;Enter&lt;/code&gt; inserisce un a-capo invece di invia il form, la combinazione per confermare mentre il focus è su una &lt;code&gt;TextArea&lt;/code&gt; diventa &lt;code&gt;Ctrl+Enter&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="nf"&gt;.text_area&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Field&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Notes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Notes"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;.placeholder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Write here..."&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;.height&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  4. Recuperare i valori: ancora niente stringhe magiche
&lt;/h2&gt;

&lt;p&gt;Una volta che il form è stato sottomesso, &lt;code&gt;values()&lt;/code&gt; consuma lo stato e restituisce un iteratore di coppie &lt;code&gt;(T, String)&lt;/code&gt; — che puoi raccogliere direttamente in una &lt;code&gt;HashMap&lt;/code&gt; tipizzata sul tuo enum, se na &lt;code&gt;enum&lt;/code&gt; implementa &lt;code&gt;Hash&lt;/code&gt; ed &lt;code&gt;Eq&lt;/code&gt; ovviamente:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;values&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;HashMap&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Field&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="nf"&gt;.values&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.collect&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;E se ti serve leggere un valore mentre il form è ancora in corso — per esempio per riflettere quanto digitato altrove nella tua UI, tipo un'anteprima live — non devi aspettare la sottomissione: &lt;code&gt;value(&amp;amp;Field::Email)&lt;/code&gt; e &lt;code&gt;value_as::&amp;lt;u16&amp;gt;(&amp;amp;Field::Port)&lt;/code&gt; — quest'ultimo per parsare direttamente in un tipo &lt;code&gt;FromStr&lt;/code&gt; — funzionano in ogni momento.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Validazione: obbligatorietà e regole di forma sono due cose distinte
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;ratiform&lt;/code&gt; separa concettualmente due domande diverse: &lt;em&gt;"questo campo può essere vuoto?"&lt;/em&gt; e &lt;em&gt;"se non è vuoto, il suo contenuto rispetta una certa forma?"&lt;/em&gt;. La prima domanda è gestita dal meccanismo &lt;code&gt;required&lt;/code&gt;/&lt;code&gt;optional&lt;/code&gt; visto sopra; la seconda da &lt;code&gt;.validator(...)&lt;/code&gt;, una funzione &lt;code&gt;Fn(&amp;amp;str) -&amp;gt; Result&amp;lt;(), String&amp;gt;&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="nf"&gt;.single_line&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Field&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;CodiceFiscale&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Codice fiscale"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;.validator&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;ratiform&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;validators&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;max_length&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Troppo lungo"&lt;/span&gt;&lt;span class="nf"&gt;.to_owned&lt;/span&gt;&lt;span class="p"&gt;()))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;La libreria include già un pacchetto di validatori comuni in &lt;code&gt;ratiform::validators&lt;/code&gt;: &lt;code&gt;min_length&lt;/code&gt;/&lt;code&gt;max_length&lt;/code&gt; (Unicode-aware), &lt;code&gt;is_numeric&lt;/code&gt;, &lt;code&gt;alphabetic&lt;/code&gt;/&lt;code&gt;alphanumeric&lt;/code&gt;, &lt;code&gt;no_whitespace&lt;/code&gt;, e &lt;code&gt;parsable::&amp;lt;T&amp;gt;&lt;/code&gt;, che sfrutta &lt;code&gt;T: FromStr&lt;/code&gt; — utile anche con tipi che non appartengono a &lt;code&gt;ratiform&lt;/code&gt;, come &lt;code&gt;parsable::&amp;lt;chrono::NaiveDate&amp;gt;(...)&lt;/code&gt; per una validazione di data corretta (bisestili inclusi) senza che &lt;code&gt;ratiform&lt;/code&gt; debba dipendere da &lt;code&gt;chrono&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Un dettaglio: un validatore non vede mai una stringa vuota. Se il campo è vuoto, decide il controllo di obbligatorietà, non il validatore — quindi nessuno dei validatori built-in (né i tuoi) deve gestire il caso speciale della stringa vuota.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. Normalizzare, non solo validare
&lt;/h2&gt;

&lt;p&gt;Dove &lt;code&gt;validator&lt;/code&gt; giudica un valore già digitato, &lt;code&gt;normalizer&lt;/code&gt; lo riscrive in una forma canonica &lt;em&gt;prima&lt;/em&gt; che la validazione lo veda:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="nf"&gt;.single_line&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Field&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;CodiceFiscale&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Codice fiscale"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;.normalizer&lt;/span&gt;&lt;span class="p"&gt;(|&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="nf"&gt;.to_uppercase&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="nf"&gt;.validator&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;ratiform&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;validators&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;max_length&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Troppo lungo"&lt;/span&gt;&lt;span class="nf"&gt;.to_owned&lt;/span&gt;&lt;span class="p"&gt;()))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Il normalizer gira a ogni tasto premuto, su &lt;code&gt;set_value&lt;/code&gt; e sul valore iniziale: il campo non viene mai visto — né dal validatore, né da &lt;code&gt;is_dirty()&lt;/code&gt;, né da &lt;code&gt;values()&lt;/code&gt; — in una forma diversa da quella normalizzata. Abbinato ad &lt;code&gt;alphabet(...)&lt;/code&gt; su un campo a riga singola, la divisione dei compiti è pulita: &lt;code&gt;alphabet&lt;/code&gt; rifiuta un carattere non ammesso, &lt;code&gt;normalizer&lt;/code&gt; riscrive uno che era ammesso ma va corretto.&lt;/p&gt;

&lt;h2&gt;
  
  
  7. Layout: orizzontale o impilato, deciso a runtime
&lt;/h2&gt;

&lt;p&gt;Di default ogni campo mostra etichetta e valore sulla stessa riga (&lt;code&gt;FormLayout::Horizontal&lt;/code&gt;). Se il terminale è stretto, &lt;code&gt;FormLayout::Stacked&lt;/code&gt; mette l'etichetta sopra il valore:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="n"&gt;frame&lt;/span&gt;&lt;span class="nf"&gt;.render_stateful_widget&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nn"&gt;Form&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;default&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.with_layout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;FormLayout&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Stacked&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="n"&gt;area&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;state&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;Dato che &lt;code&gt;Form&lt;/code&gt; viene ricostruito a ogni frame, nulla impedisce di scegliere il layout in base alla larghezza disponibile in quel momento — è esattamente quello che fa &lt;code&gt;examples/layouts.rs&lt;/code&gt;, passando a &lt;code&gt;Stacked&lt;/code&gt; quando il terminale si stringe, senza bisogno di codice dedicato per intercettare il resize.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Horizontal&lt;/code&gt; e &lt;code&gt;Stacked&lt;/code&gt; bastano finché la forma del form è "una riga per campo". Ma un indirizzo di spedizione, per dire, ha una sua geometria naturale: via su una riga intera, poi città/provincia/CAP spartiti su tre colonne di larghezza diversa. Per questi casi c'è una terza variante, &lt;code&gt;FormLayout::Custom&lt;/code&gt;, che descrive il form come una griglia esplicita di righe e colonne, cella per cella:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Email                   Password
_______________________ ____________________

Address
____________________________________________

City                  State          Zip
_____________________ ______________ _______
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ogni cella della griglia è una coppia &lt;code&gt;(Constraint, contenuto)&lt;/code&gt;: il &lt;code&gt;Constraint&lt;/code&gt; è lo stesso tipo di Ratatui che già usi per i layout normali (&lt;code&gt;Length&lt;/code&gt;, &lt;code&gt;Fill&lt;/code&gt;, ...), il contenuto dichiara &lt;em&gt;cosa&lt;/em&gt; disegnare in quella cella — l'etichetta di un campo (&lt;code&gt;Label&lt;/code&gt;), il suo widget di input (&lt;code&gt;Value&lt;/code&gt;), il suo messaggio di errore (&lt;code&gt;Error&lt;/code&gt;) — oppure niente, per uno spaziatore. Il modo più leggibile per scriverla è la macro &lt;code&gt;custom_layout!&lt;/code&gt;, che rispecchia la griglia riga per riga:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;ratiform&lt;/span&gt;&lt;span class="p"&gt;::{&lt;/span&gt;&lt;span class="n"&gt;Form&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;FormLayout&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nn"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;FormBuilder&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;custom_layout&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;grid_layout&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nd"&gt;custom_layout!&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Email | Password&lt;/span&gt;
    &lt;span class="n"&gt;row&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Constraint&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;Fill&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nf"&gt;Label&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Field&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Email&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Constraint&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;Fill&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nf"&gt;Label&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Field&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Password&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="n"&gt;row&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Constraint&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;Fill&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nf"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Field&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Email&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Constraint&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;Fill&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nf"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Field&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Password&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="n"&gt;row&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Constraint&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;Length&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nf"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Field&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Email&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Constraint&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;Fill&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nf"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Field&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Password&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;

    &lt;span class="c1"&gt;// Address&lt;/span&gt;
    &lt;span class="n"&gt;row&lt;/span&gt; &lt;span class="p"&gt;[(&lt;/span&gt;&lt;span class="nn"&gt;Constraint&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;Fill&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nf"&gt;Label&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Field&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Address&lt;/span&gt;&lt;span class="p"&gt;))],&lt;/span&gt;
    &lt;span class="n"&gt;row&lt;/span&gt; &lt;span class="p"&gt;[(&lt;/span&gt;&lt;span class="nn"&gt;Constraint&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;Fill&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nf"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Field&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Address&lt;/span&gt;&lt;span class="p"&gt;))],&lt;/span&gt;
    &lt;span class="n"&gt;row&lt;/span&gt; &lt;span class="p"&gt;[(&lt;/span&gt;&lt;span class="nn"&gt;Constraint&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;Fill&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nf"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Field&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Address&lt;/span&gt;&lt;span class="p"&gt;))],&lt;/span&gt;

    &lt;span class="c1"&gt;// City | State | Zip&lt;/span&gt;
    &lt;span class="n"&gt;row&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Constraint&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;Fill&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nf"&gt;Label&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Field&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;City&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Constraint&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;Fill&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nf"&gt;Label&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Field&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;State&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Constraint&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;Length&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nf"&gt;Label&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Field&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Zip&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="n"&gt;row&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Constraint&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;Fill&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nf"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Field&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;City&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Constraint&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;Fill&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nf"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Field&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;State&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Constraint&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;Length&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nf"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Field&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Zip&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="n"&gt;row&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Constraint&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;Fill&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nf"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Field&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;City&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Constraint&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;Fill&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nf"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Field&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;State&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Constraint&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;Length&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nf"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Field&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Zip&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;let&lt;/span&gt; &lt;span class="n"&gt;form&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Form&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;default&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.with_layout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;FormLayout&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;Custom&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;grid_layout&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Da notare tre cose:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Etichetta, valore ed errore sono celle indipendenti.&lt;/strong&gt; Non è un dettaglio decorativo: puoi mettere l'etichetta di &lt;code&gt;Email&lt;/code&gt; sopra il suo valore, ma allineata sulla stessa riga dell'etichetta di &lt;code&gt;Password&lt;/code&gt; — cosa che nessuna combinazione di &lt;code&gt;Horizontal&lt;/code&gt;/&lt;code&gt;Stacked&lt;/code&gt; permette, perché lì le tre parti di un campo restano sempre un blocco unico.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Uno spaziatore è una cella con contenuto &lt;code&gt;None&lt;/code&gt;&lt;/strong&gt; invece di uno dei tre identificatori — utile per separare visivamente gruppi di campi senza inventarsi un campo fittizio.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Il focus segue comunque l'ordine di dichiarazione dei campi nel builder, non l'ordine sulla griglia.&lt;/strong&gt; Se la griglia rispecchia la sequenza &lt;code&gt;Email → Password → Address → ...&lt;/code&gt; usata in &lt;code&gt;single_line(...)&lt;/code&gt;, &lt;code&gt;Tab&lt;/code&gt; si muove nell'ordine "naturale" che ci si aspetta guardando lo schermo; se le due sequenze divergono, &lt;code&gt;Tab&lt;/code&gt; continua a funzionare, ma salta da un punto all'altro dello schermo in un ordine che l'occhio non prevede. Vale anche l'inverso: un campo dimenticato nella griglia riceve comunque il focus quando gli tocca — semplicemente senza un cursore visibile e senza un posto dove mostrare un eventuale errore.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Chi preferisce assemblare la griglia in modo programmatico — righe generate da un ciclo, per esempio — ha a disposizione &lt;code&gt;CustomLayout::builder()&lt;/code&gt;, l'equivalente fluente della stessa macro:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;grid_layout&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;CustomLayout&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="nf"&gt;.row&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="nf"&gt;.label&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Constraint&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;Fill&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nn"&gt;Field&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Email&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;.label&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Constraint&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;Fill&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nn"&gt;Field&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Password&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;.row&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="nf"&gt;.value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Constraint&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;Fill&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nn"&gt;Field&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Email&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;.value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Constraint&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;Fill&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nn"&gt;Field&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Password&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;.build&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Infine, &lt;code&gt;.with_column_gap(n)&lt;/code&gt; su &lt;code&gt;CustomLayout&lt;/code&gt; regola lo spazio orizzontale tra colonne adiacenti della stessa riga (di default 1) — la prima colonna di ogni riga non viene mai preceduta da spaziatura ovviamente.&lt;/p&gt;

&lt;h2&gt;
  
  
  8. Theming: quando il grigio di default non basta
&lt;/h2&gt;

&lt;p&gt;Di default, &lt;code&gt;Form::default()&lt;/code&gt; disegna con uno schema grigio/grassetto/invertito. Per personalizzarlo si costruisce un &lt;code&gt;FormStyle&lt;/code&gt; e lo si passa a &lt;code&gt;Form::with_style(...)&lt;/code&gt; — fin qui nulla di sorprendente. Quello che fa la differenza è &lt;em&gt;come&lt;/em&gt; si descrive quel &lt;code&gt;FormStyle&lt;/code&gt;: un piccolo motore di regole dove ogni regola dichiara &lt;em&gt;a chi&lt;/em&gt; si applica, su tre assi indipendenti:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;Widgets&lt;/code&gt;&lt;/strong&gt; — quale tipo di campo: &lt;code&gt;SINGLE_LINE&lt;/code&gt;, &lt;code&gt;TEXT_AREA&lt;/code&gt;, &lt;code&gt;CHECK_BOX&lt;/code&gt;, &lt;code&gt;SELECT&lt;/code&gt;, &lt;code&gt;MULTI_SELECT&lt;/code&gt;, o &lt;code&gt;ANY&lt;/code&gt; per tutti.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;Parts&lt;/code&gt;&lt;/strong&gt; — quale parte visiva di quel campo: &lt;code&gt;LABEL&lt;/code&gt; (l'etichetta), &lt;code&gt;AREA&lt;/code&gt; (lo sfondo del riquadro), &lt;code&gt;TEXT&lt;/code&gt; (il testo digitato), &lt;code&gt;PLACEHOLDER&lt;/code&gt;, &lt;code&gt;MARKER&lt;/code&gt; (il simbolo &lt;code&gt;[x]&lt;/code&gt; di una checkbox, o il pallino di una multi-select), &lt;code&gt;ITEM&lt;/code&gt;/&lt;code&gt;ACTIVE&lt;/code&gt;/&lt;code&gt;SELECTED&lt;/code&gt; (le righe di una select e quale di esse ha il cursore o è scelta), &lt;code&gt;ERROR&lt;/code&gt;, o &lt;code&gt;ANY&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;States&lt;/code&gt;&lt;/strong&gt; — lo stato del campo in quel momento: &lt;code&gt;NORMAL&lt;/code&gt;, &lt;code&gt;FOCUSED&lt;/code&gt;, &lt;code&gt;DISABLED&lt;/code&gt;, &lt;code&gt;READ_ONLY&lt;/code&gt;, o &lt;code&gt;ANY&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Ognuna delle tre è una maschera di bit che si combina con &lt;code&gt;|&lt;/code&gt; — &lt;code&gt;Widgets::SINGLE_LINE | Widgets::TEXT_AREA&lt;/code&gt; è una regola valida quanto una singola costante. Una regola si scrive con &lt;code&gt;FormStyleBuilder::add(widgets, parts, states, style)&lt;/code&gt;, e se ne dichiarano quante servono:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;ratatui&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;style&lt;/span&gt;&lt;span class="p"&gt;::{&lt;/span&gt;&lt;span class="n"&gt;Color&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Style&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;ratiform&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;style&lt;/span&gt;&lt;span class="p"&gt;::{&lt;/span&gt;&lt;span class="n"&gt;FormStyle&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Parts&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;States&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Widgets&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;label&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Style&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;default&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.fg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Color&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Cyan&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Style&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;default&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.fg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Color&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;White&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;my_style&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;FormStyle&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="nf"&gt;.add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Widgets&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;ANY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nn"&gt;Parts&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;LABEL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nn"&gt;States&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;NORMAL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;label&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;.add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Widgets&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;ANY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nn"&gt;Parts&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;LABEL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nn"&gt;States&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;FOCUSED&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;label&lt;/span&gt;&lt;span class="nf"&gt;.bold&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="nf"&gt;.add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nn"&gt;Widgets&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;ANY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nn"&gt;Parts&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;TEXT&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nn"&gt;Parts&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;ITEM&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nn"&gt;Parts&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;MARKER&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nn"&gt;States&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;NORMAL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;.add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nn"&gt;Widgets&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;ANY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nn"&gt;Parts&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;TEXT&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nn"&gt;Parts&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;ITEM&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nn"&gt;Parts&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;MARKER&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nn"&gt;States&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;FOCUSED&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="nf"&gt;.bold&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;.add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nn"&gt;Widgets&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;ANY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nn"&gt;Parts&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;AREA&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nn"&gt;Parts&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;ACTIVE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nn"&gt;States&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;FOCUSED&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="nf"&gt;.bg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Color&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Blue&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;.add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nn"&gt;Widgets&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;ANY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nn"&gt;Parts&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;ERROR&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nn"&gt;States&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;ANY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nn"&gt;Style&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;default&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.bg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Color&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Red&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;.fg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Color&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;White&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;.bold&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;.build&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="n"&gt;frame&lt;/span&gt;&lt;span class="nf"&gt;.render_stateful_widget&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Form&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;default&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.with_style&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;my_style&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;area&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Da questo esempio (ripreso da &lt;code&gt;examples/theming.rs&lt;/code&gt;) si vedono i due vantaggi concreti rispetto alle cinque caselle fisse: &lt;code&gt;TEXT&lt;/code&gt;, &lt;code&gt;ITEM&lt;/code&gt; e &lt;code&gt;MARKER&lt;/code&gt; — cioè "il contenuto vero e proprio", che sia testo digitato, riga di una select o marker di una checkbox — condividono la stessa regola in un colpo solo, invece di essere tre proprietà separate da tenere sincronizzate a mano; e &lt;code&gt;AREA | ACTIVE&lt;/code&gt; fa lo stesso per l'evidenziazione, che si tratti dello sfondo di un &lt;code&gt;SingleLine&lt;/code&gt; a fuoco o della riga attiva di una &lt;code&gt;Select&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Le regole si dichiarano in qualunque ordine.&lt;/strong&gt; &lt;code&gt;FormStyleBuilder::build()&lt;/code&gt; le ordina da sé per specificità prima di risolvere eventuali sovrapposizioni: una regola che nomina un solo widget batte una che ne nomina cinque con &lt;code&gt;ANY&lt;/code&gt;, anche se quest'ultima è stata scritta dopo; lo stesso vale, in cascata, per &lt;code&gt;Parts&lt;/code&gt; e poi per &lt;code&gt;States&lt;/code&gt;. L'ordine di dichiarazione conta solo come spareggio finale, quando due regole sono ugualmente specifiche — in quel caso vince l'ultima scritta. In pratica: puoi partire da una regola larga (&lt;code&gt;Widgets::ANY, Parts::ANY, States::ANY, normal&lt;/code&gt;) come base di tutto il form, e poi affinarla con regole via via più mirate, senza doverti preoccupare di che riga viene prima nel codice.&lt;/p&gt;

&lt;p&gt;Il tema di default stesso è costruito con lo stesso identico meccanismo — non è un caso speciale, è solo un &lt;code&gt;FormStyle::builder()&lt;/code&gt; con un certo insieme di regole già scritto per te: sfondo scuro per l'area di &lt;code&gt;SingleLine&lt;/code&gt;/&lt;code&gt;TextArea&lt;/code&gt;, grassetto per etichetta e contenuto quando il campo ha il focus, colori invertiti per la riga attiva di una select, rosso e grassetto per gli errori, corsivo grigio per i placeholder, e barrato uniforme — su ogni parte, con un'unica regola &lt;code&gt;Parts::ANY&lt;/code&gt; — per i campi disabilitati.&lt;/p&gt;

&lt;h2&gt;
  
  
  Chiudendo il cerchio
&lt;/h2&gt;

&lt;p&gt;Il filo conduttore, dal primo campo al theming completo, è sempre lo stesso: &lt;code&gt;ratiform&lt;/code&gt; possiede input, focus, validazione e navigazione — cioè esattamente la parte che diventa dolorosa da scrivere a mano oltre il secondo campo — ma non possiede mai il tuo modello dati. L'identificatore resta un tuo tipo dall'inizio alla fine, il valore torna sempre come &lt;code&gt;String&lt;/code&gt; legata a quell'identificatore, e nessun passaggio nel mezzo ti obbliga a inventarti un formato di interscambio per dati che il compilatore conosceva già in partenza.&lt;/p&gt;

&lt;p&gt;Detto cosa fa, vale la pena essere altrettanto chiari su cosa &lt;code&gt;ratiform&lt;/code&gt; non fa:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;non è un framework applicativo: possiede focus, input e validazione dei singoli campi, non la logica di dominio, il routing tra schermate o la persistenza dei dati;&lt;/li&gt;
&lt;li&gt;non gestisce l'event loop: sei tu a leggere gli eventi da &lt;code&gt;crossterm&lt;/code&gt; e a passare ogni &lt;code&gt;KeyEvent&lt;/code&gt; a &lt;code&gt;handle_input(...)&lt;/code&gt;;&lt;/li&gt;
&lt;li&gt;non converte automaticamente il form in una tua &lt;code&gt;struct&lt;/code&gt;: &lt;code&gt;values()&lt;/code&gt; restituisce coppie &lt;code&gt;(T, String)&lt;/code&gt;, il passaggio a un tipo tipizzato resta a tuo carico;&lt;/li&gt;
&lt;li&gt;non gestisce il mouse: &lt;code&gt;handle_input&lt;/code&gt; accetta solo eventi da tastiera.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;ratiform&lt;/code&gt; è ancora in versione 0.x: l'API pubblica può quindi evolvere, anche se le idee centrali — identificatori tipizzati, separazione tra builder, stato e widget, validazione e normalizzazione — sono ormai abbastanza stabili.&lt;/p&gt;

&lt;p&gt;Il codice, gli esempi completi e il changelog sono sul &lt;a href="https://github.com/marc0x71/ratiform" rel="noopener noreferrer"&gt;repository GitHub&lt;/a&gt;; la crate è pubblicata su &lt;a href="https://crates.io/crates/ratiform" rel="noopener noreferrer"&gt;crates.io&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>rust</category>
      <category>ratatui</category>
    </item>
    <item>
      <title>Ratatui passo dopo passo - Introduzione</title>
      <dc:creator>Marco Bollero</dc:creator>
      <pubDate>Sun, 06 Sep 2026 14:32:32 +0000</pubDate>
      <link>https://dev.to/marco_bollero_ba3c38ddd27/ratatui-passo-dopo-passo-introduzione-548l</link>
      <guid>https://dev.to/marco_bollero_ba3c38ddd27/ratatui-passo-dopo-passo-introduzione-548l</guid>
      <description>&lt;h2&gt;
  
  
  Una nota personale
&lt;/h2&gt;

&lt;p&gt;Nel 2000 lavoravo principalmente su Windows NT — stavo pure prendendo una certificazione — quando mi hanno assegnato a un nuovo progetto che doveva collegarsi a server Unix. Il mio collega, in affiancamento, mi dice: "apri il terminale, PuTTY". Io, tranquillo, doppio click sull'icona. Poi: "seleziona questo server". Doppio click. Poi: "metti la finestra a tutto schermo". Doppio click, tutto contento, sapevo esattamente cosa fare.&lt;/p&gt;

&lt;p&gt;E poi lui: "ora quel mouse non ti serve più, puoi anche staccarlo".&lt;/p&gt;

&lt;p&gt;Panico. Avevo iniziato col Commodore 64, altro che Windows, poi MS-DOS — la tastiera non mi era certo estranea. Ma erano passati anni, e ritrovarmi lì, su un sistema Unix, senza più il mouse a cui appoggiarmi, mi ha fatto pensare per un attimo: &lt;em&gt;ora mi cacciano&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Non mi hanno cacciato. È stata semplicemente la fine del mio attaccamento al mouse. Oggi lavoro quasi esclusivamente da tastiera — Sway come window manager, tmux, nvim — e quando devo aprire Firefox mi scoccia quasi cercarlo. Questa serie nasce anche da lì: dal fatto che il terminale, una volta che smetti di temerlo, diventa lo strumento più diretto che hai.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cos'è Ratatui
&lt;/h2&gt;

&lt;p&gt;Ratatui è una libreria Rust per costruire interfacce interattive che vivono interamente nel terminale: niente finestre, niente mouse (a meno che tu non lo voglia), solo caratteri, colori e un layout che tu controlli riga per riga. Se hai mai usato &lt;code&gt;htop&lt;/code&gt; o &lt;code&gt;lazygit&lt;/code&gt;, hai già usato il tipo di applicazione che Ratatui ti mette in condizione di costruire: quelle hanno una TUI, &lt;em&gt;terminal user interface&lt;/em&gt; (o qualcuno preferisce &lt;em&gt;text user interface&lt;/em&gt;), e sono l'equivalente testuale di una GUI — pannelli, liste selezionabili, barre di stato, il tutto renderizzato con caratteri invece che con pixel.&lt;/p&gt;

&lt;p&gt;Non è un framework che nasconde il terminale dietro un'astrazione: è una libreria pensata per dare controllo diretto su cosa appare a schermo.&lt;/p&gt;

&lt;p&gt;Oggi trovi TUI scritte in Rust ovunque: client Git, monitor di sistema, gestori di database, dashboard di infrastruttura. Ratatui è uno dei nomi che incontrerai più spesso nell’ecosistema Rust quando si parla di TUI.&lt;/p&gt;

&lt;h2&gt;
  
  
  A chi si rivolge questa serie
&lt;/h2&gt;

&lt;p&gt;Questa serie parte dal presupposto che tu conosca già Rust — ownership, trait, &lt;code&gt;match&lt;/code&gt;, closure — ma non abbia mai toccato Ratatui. Non troverai spiegazioni di sintassi di base del linguaggio, ma nemmeno voli pindarici sull'architettura interna della libreria: l'obiettivo di ogni articolo è farti scrivere codice che produce qualcosa di visibile sul terminale, un tassello alla volta, riusando sempre quello scritto nella puntata precedente.&lt;/p&gt;

&lt;p&gt;Serve solo Rust installato e un terminale. Nient'altro.&lt;/p&gt;

&lt;h2&gt;
  
  
  Come è strutturata la serie
&lt;/h2&gt;

&lt;p&gt;Si parte dal minimo indispensabile — una schermata vuota con una riga di testo — e si arriva, passo dopo passo, a un'applicazione con stato, più widget ed eventi che arrivano anche da un thread in background. Ogni tappa aggiunge un solo concetto nuovo rispetto alla precedente.&lt;/p&gt;

&lt;p&gt;Questa è la traccia che ho in mente al momento: potrebbe cambiare strada facendo, soprattutto se qualche argomento si rivelerà abbastanza interessante da meritarsi una puntata tutta sua.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Hello Ratatui&lt;/strong&gt; — una schermata minima e un &lt;code&gt;Paragraph&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Testo&lt;/strong&gt; — &lt;code&gt;Span&lt;/code&gt;, &lt;code&gt;Line&lt;/code&gt;, &lt;code&gt;Text&lt;/code&gt; e &lt;code&gt;Paragraph&lt;/code&gt;, dal componente più piccolo al più capace.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Layout base&lt;/strong&gt; — dividere lo schermo in aree con &lt;code&gt;Layout&lt;/code&gt; e &lt;code&gt;Constraint&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;Block&lt;/code&gt;&lt;/strong&gt; — bordi, titoli e padding.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Input da tastiera&lt;/strong&gt; — leggere tasti specifici con &lt;code&gt;KeyCode&lt;/code&gt;, non solo "un tasto qualsiasi".&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Gestire lo stato dell'app&lt;/strong&gt; — una struct &lt;code&gt;App&lt;/code&gt; e il ciclo evento → aggiornamento → ridisegno.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Un text input basilare&lt;/strong&gt; — costruirsi da soli un campo di testo, cursore compreso.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Un widget alla volta: &lt;code&gt;List&lt;/code&gt; e &lt;code&gt;Table&lt;/code&gt;&lt;/strong&gt; — la selezione come stato, con &lt;code&gt;ListState&lt;/code&gt; e &lt;code&gt;TableState&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Organizzare il progetto su più file&lt;/strong&gt; — moduli separati e un enum per generalizzare gli eventi.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Aggiornamenti in background con i thread&lt;/strong&gt; — un thread separato che produce dati e li invia con &lt;code&gt;std::sync::mpsc&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Async e aggiornamenti in background&lt;/strong&gt; — la stessa idea, ma con un runtime asincrono.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;E probabilmente non finirà qui.&lt;/p&gt;

&lt;p&gt;Detto questo: perdersi in chiacchiere ogni tanto fa bene, ma direi che per oggi abbiamo esagerato. Si comincia dal primo passo: una schermata vuota, e la prima riga di testo che ci scriviamo dentro.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Questo articolo è stato pubblicato originariamente sul mio &lt;a href="https://marc0x71.github.io/blog/ratatui-into/" rel="noopener noreferrer"&gt;blog personale&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>rust</category>
      <category>ratatui</category>
      <category>terminal</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Switching from C/C++ to Rust: the invisible checklist</title>
      <dc:creator>Marco Bollero</dc:creator>
      <pubDate>Mon, 02 Feb 2026 14:00:00 +0000</pubDate>
      <link>https://dev.to/marco_bollero_ba3c38ddd27/switching-from-cc-to-rust-the-invisible-checklist-2p9n</link>
      <guid>https://dev.to/marco_bollero_ba3c38ddd27/switching-from-cc-to-rust-the-invisible-checklist-2p9n</guid>
      <description>&lt;p&gt;After years of writing code in C and C++, switching to Rust forced me into a reflection I wasn't expecting. It's not about syntax, performance, or language features. It's about something more subtle: &lt;strong&gt;where I spend my mental energy while programming&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The invisible checklist
&lt;/h2&gt;

&lt;p&gt;When you write in C or C++, there's a checklist you have to keep running in your head at all times. It's not written anywhere, it doesn't show up in any warning, but it's there:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Could this pointer be null?&lt;/li&gt;
&lt;li&gt;Did I free this memory? Did I free it twice?&lt;/li&gt;
&lt;li&gt;Will this reference still be valid when I use it?&lt;/li&gt;
&lt;li&gt;Is this cast safe?&lt;/li&gt;
&lt;li&gt;Am I invoking undefined behavior without knowing it?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It's an &lt;strong&gt;invisible&lt;/strong&gt; burden. You don't perceive it as an obstacle because it's become the norm. It's the constant background noise of every line of code you write. And the most insidious problem is that feedback, when it comes, comes &lt;strong&gt;late&lt;/strong&gt;: a crash in production, a bug report weeks later, a sanitizer telling you that the code that "worked" didn't actually work at all.&lt;/p&gt;

&lt;p&gt;Or worse: it never comes. The code runs, seems to work, but it's invoking undefined behavior that just happens not to manifest. Until it does.&lt;/p&gt;

&lt;h2&gt;
  
  
  The "no" that comes immediately
&lt;/h2&gt;

&lt;p&gt;I'll admit my early days with Rust weren't exactly smooth. The borrow checker kept stopping me. Things I would have written in thirty seconds in C++ required rethinking, restructuring, sometimes complete rewrites of my approach.&lt;/p&gt;

&lt;p&gt;But then I realized something: that "no" coming immediately was &lt;strong&gt;a gift&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;When the compiler stops you, something important happens:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;You're still in the mental context of the problem.&lt;/strong&gt; You don't have to reconstruct weeks later what you were thinking when you wrote that code.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;You can fix it while you're still reasoning.&lt;/strong&gt; The solution is still fresh, the alternatives are still visible.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;You learn why that thing is problematic.&lt;/strong&gt; The error message (often surprisingly helpful) explains &lt;em&gt;what's&lt;/em&gt; wrong and &lt;em&gt;why&lt;/em&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;It's the difference between a teacher who corrects you while you speak and one who gives you a grade three months later without explaining where you went wrong.&lt;/p&gt;

&lt;h2&gt;
  
  
  Two types of muscle memory
&lt;/h2&gt;

&lt;p&gt;There's another difference I noticed, more subtle.&lt;/p&gt;

&lt;p&gt;In C++, the muscle memory you develop over time is &lt;strong&gt;avoidant&lt;/strong&gt;. You learn &lt;em&gt;not to do&lt;/em&gt; certain things. It's a negative memory, not in a pejorative sense, but in the sense that you have to remember what &lt;em&gt;not&lt;/em&gt; to do rather than what to do: a list of patterns to avoid, of traps to dodge. And this list keeps growing, because the language doesn't prevent you from falling into the traps, you just have to remember they exist.&lt;/p&gt;

&lt;p&gt;In Rust, muscle memory is &lt;strong&gt;constructive&lt;/strong&gt;. You learn patterns that are &lt;em&gt;inherently&lt;/em&gt; correct. You don't have to remember what to avoid because the compiler won't let you do it. Instead of thinking "I must remember not to leave the door open", you learn to build a door that closes by itself.&lt;/p&gt;

&lt;p&gt;This frees up mental space. Space I can use to think about domain logic, architecture, the problem I'm actually trying to solve, instead of tripping over my own mistakes.&lt;/p&gt;

&lt;h2&gt;
  
  
  It's not about "better" or "worse"
&lt;/h2&gt;

&lt;p&gt;I'm not saying C or C++ are wrong languages, or that people who use them are making a mistake. They have their legitimate use cases, mature ecosystems, decades of existing code that works.&lt;/p&gt;

&lt;p&gt;The question I asked myself is different: &lt;strong&gt;where do I prefer to spend my cognitive energy?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Some programmers prefer total freedom and accept the responsibility that comes with it. That's a legitimate choice. Others, and I count myself among them, prefer tighter constraints that free up mental bandwidth to focus on other things.&lt;/p&gt;

&lt;p&gt;The cost exists in both cases. In C++ it's distributed over time, invisible, perpetual. In Rust it's concentrated at the beginning, explicit, and decreases as you internalize the patterns.&lt;/p&gt;

&lt;p&gt;For me, the second trade-off is more favorable. Not because it's objectively better, but because it fits better with how my head works, and with the kind of mistakes I tend to make.&lt;/p&gt;

&lt;h2&gt;
  
  
  A final thought
&lt;/h2&gt;

&lt;p&gt;What surprised me most about Rust wasn't the speed, or the language features, or the ecosystem. It was the &lt;strong&gt;feeling&lt;/strong&gt; of programming.&lt;/p&gt;

&lt;p&gt;That invisible checklist I'd been carrying in my head for years? It's gone. Or rather: it's been externalized. The compiler holds it for me.&lt;/p&gt;

&lt;p&gt;And this, in the end, made me realize how heavy it was to carry.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;This post was originally written in Italian and is available &lt;a href="https://dev.to/marco_bollero_ba3c38ddd27/passare-da-c-a-rust-la-checklist-invisibile-167d"&gt;here&lt;/a&gt;. Translated to English with the help of AI.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>programming</category>
      <category>cpp</category>
      <category>c</category>
      <category>rust</category>
    </item>
    <item>
      <title>Passare da C/C++ a Rust: la checklist invisibile</title>
      <dc:creator>Marco Bollero</dc:creator>
      <pubDate>Mon, 02 Feb 2026 08:57:03 +0000</pubDate>
      <link>https://dev.to/marco_bollero_ba3c38ddd27/passare-da-c-a-rust-la-checklist-invisibile-167d</link>
      <guid>https://dev.to/marco_bollero_ba3c38ddd27/passare-da-c-a-rust-la-checklist-invisibile-167d</guid>
      <description>&lt;p&gt;Dopo anni passati a scrivere codice in C e C++, il passaggio a Rust mi ha costretto a una riflessione che non mi aspettavo. Non riguarda la sintassi, le performance, o le feature del linguaggio. Riguarda qualcosa di più sottile: &lt;strong&gt;dove spendo le mie energie mentali mentre programmo&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  La checklist invisibile
&lt;/h2&gt;

&lt;p&gt;Quando scrivi in C o C++, c'è una checklist che devi tenere sempre attiva nella testa. Non è scritta da nessuna parte, non appare in nessun warning, ma è lì:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Questo puntatore potrebbe essere null?&lt;/li&gt;
&lt;li&gt;Ho liberato questa memoria? L'ho liberata due volte?&lt;/li&gt;
&lt;li&gt;Questa reference sarà ancora valida quando la userò?&lt;/li&gt;
&lt;li&gt;Questo cast è sicuro?&lt;/li&gt;
&lt;li&gt;Sto invocando undefined behavior senza saperlo?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;È una fatica &lt;strong&gt;invisibile&lt;/strong&gt;. Non la percepisci come ostacolo perché è diventata la normalità. È il sottofondo costante di ogni riga di codice che scrivi. E il problema più insidioso è che il feedback, quando arriva, arriva &lt;strong&gt;tardi&lt;/strong&gt;: un crash in produzione, un bug report settimane dopo, un sanitizer che ti dice che quel codice che "funzionava" in realtà non funzionava affatto.&lt;/p&gt;

&lt;p&gt;O peggio: non arriva mai. Il codice gira, sembra funzionare, ma sta invocando undefined behavior che per puro caso non si manifesta. Fino a quando non lo fa.&lt;/p&gt;

&lt;h2&gt;
  
  
  Il "no" che arriva subito
&lt;/h2&gt;

&lt;p&gt;Ammetto che i primi tempi con Rust non sono stati semplicissimi. Il borrow checker mi bloccava in continuazione. Cose che in C++ avrei scritto in trenta secondi richiedevano ripensamenti, ristrutturazioni, a volte riscritture complete dell'approccio.&lt;/p&gt;

&lt;p&gt;Ma poi ho realizzato una cosa: quel "no" che arrivava subito era &lt;strong&gt;un regalo&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Quando il compilatore ti ferma, succede qualcosa di importante:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Sei ancora nel contesto mentale del problema.&lt;/strong&gt; Non devi ricostruire settimane dopo cosa stavi pensando quando hai scritto quel codice.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Puoi correggere mentre ragioni.&lt;/strong&gt; La soluzione è ancora fresca, le alternative sono ancora visibili.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Impari perché quella cosa è problematica.&lt;/strong&gt; Il messaggio di errore (spesso sorprendentemente utile) ti spiega &lt;em&gt;cosa&lt;/em&gt; non va e &lt;em&gt;perché&lt;/em&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;È la differenza tra un insegnante che ti corregge mentre parli e uno che ti dà un voto tre mesi dopo senza spiegarti dove hai sbagliato.&lt;/p&gt;

&lt;h2&gt;
  
  
  Due tipi di "muscle memory"
&lt;/h2&gt;

&lt;p&gt;C'è un'altra differenza che ho notato, più sottile.&lt;/p&gt;

&lt;p&gt;In C++, la "muscle memory" che sviluppi nel tempo è di tipo &lt;strong&gt;evitativo&lt;/strong&gt;. Impari a &lt;em&gt;non fare&lt;/em&gt; certe cose. È una memoria negativa, non in senso dispregiativo, ma nel senso che devi ricordare cosa &lt;em&gt;non&lt;/em&gt; fare invece di cosa fare: una lista di pattern da evitare, di trappole da schivare. E questa lista cresce continuamente, perché il linguaggio non ti impedisce di cadere nelle trappole, devi solo ricordarti che esistono.&lt;/p&gt;

&lt;p&gt;In Rust, la muscle memory è di tipo &lt;strong&gt;costruttivo&lt;/strong&gt;. Impari pattern che sono &lt;em&gt;intrinsecamente&lt;/em&gt; corretti. Non devi ricordare cosa evitare perché il compilatore non ti permette di farlo. Invece di pensare "devo ricordarmi di non lasciare la porta aperta", impari a costruire una porta che si chiude da sola.&lt;/p&gt;

&lt;p&gt;Questo libera spazio mentale. Spazio che posso usare per pensare alla logica del dominio, all'architettura, al problema che sto effettivamente cercando di risolvere, invece che a non inciampare nei miei stessi errori.&lt;/p&gt;

&lt;h2&gt;
  
  
  Non è una questione di "meglio" o "peggio"
&lt;/h2&gt;

&lt;p&gt;Non sto dicendo che C o C++ siano linguaggi sbagliati, o che chi li usa stia facendo un errore. Hanno i loro contesti d'uso legittimi, ecosistemi maturi, decenni di codice esistente che funziona.&lt;/p&gt;

&lt;p&gt;La domanda che mi sono posto è diversa: &lt;strong&gt;dove preferisco spendere le mie energie cognitive?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Alcuni programmatori preferiscono la libertà totale e accettano la responsabilità che ne deriva. È una scelta legittima. Altri, e mi ci metto dentro, preferiscono vincoli più stretti che liberano bandwidth mentale per concentrarsi su altro.&lt;/p&gt;

&lt;p&gt;Il costo c'è in entrambi i casi. In C++ è distribuito nel tempo, invisibile, perpetuo. In Rust è concentrato all'inizio, esplicito, e diminuisce man mano che interiorizzi i pattern.&lt;/p&gt;

&lt;p&gt;Per me, il secondo trade-off è più favorevole. Non perché sia oggettivamente migliore, ma perché si adatta meglio al modo in cui funziona la mia testa, e al tipo di errori che tendo a fare.&lt;/p&gt;

&lt;h2&gt;
  
  
  Una riflessione finale
&lt;/h2&gt;

&lt;p&gt;La cosa che più mi ha sorpreso di Rust non è stata la velocità, o le feature del linguaggio, o l'ecosistema. È stata la &lt;strong&gt;sensazione&lt;/strong&gt; di programmare.&lt;/p&gt;

&lt;p&gt;Quella checklist invisibile che portavo nella testa da anni? Non c'è più. O meglio: è stata esternalizzata. Il compilatore la tiene per me.&lt;/p&gt;

&lt;p&gt;E questo, alla fine, mi ha fatto capire quanto fosse pesante portarla.&lt;/p&gt;

</description>
      <category>programming</category>
      <category>cpp</category>
      <category>rust</category>
      <category>c</category>
    </item>
    <item>
      <title>Il patto delle dipendenze: quando diventa un Contratto col Diavolo</title>
      <dc:creator>Marco Bollero</dc:creator>
      <pubDate>Wed, 28 Jan 2026 08:44:21 +0000</pubDate>
      <link>https://dev.to/marco_bollero_ba3c38ddd27/il-patto-delle-dipendenze-quando-diventa-un-contratto-col-diavolo-4m8k</link>
      <guid>https://dev.to/marco_bollero_ba3c38ddd27/il-patto-delle-dipendenze-quando-diventa-un-contratto-col-diavolo-4m8k</guid>
      <description>&lt;p&gt;Ogni volta che scrivo &lt;code&gt;cargo add qualcosa&lt;/code&gt;, mi piace pensare che sto semplicemente aggiungendo una funzionalità al mio progetto. È comodo, è veloce, è moderno. Ma se sono onesto con me stesso, quello che sto davvero facendo è firmare un contratto trilaterale: tra me, una libreria scritta da uno sconosciuto su internet, e l'utente finale che si fida ciecamente del mio software.&lt;/p&gt;

&lt;p&gt;E come tutti i contratti che firmiamo senza leggere, le clausole scritte in piccolo prima o poi vengono a bussare alla porta.&lt;/p&gt;

&lt;h2&gt;
  
  
  Il giorno in cui tutto va a puttane
&lt;/h2&gt;

&lt;p&gt;Immaginati questa scena, che probabilmente hai già vissuto: sono le 3 del pomeriggio di venerdì. Il cliente ti chiama incazzato nero perché l'applicazione che hai deployato la settimana scorsa sta perdendo dati. Non pochi dati. Dati importanti. Dati che valgono soldi veri.&lt;/p&gt;

&lt;p&gt;Tu apri il progetto, guardi il codice che hai scritto. È perfetto. Compila, i test passano, la logica è cristallina. Ma c'è un problema: il bug non è nel TUO codice. È in una delle quaranta dipendenze che hai nel Cargo.toml. O peggio ancora, in una delle centocinquanta dipendenze transitive che non sapevi nemmeno di avere.&lt;/p&gt;

&lt;p&gt;Benvenuto nel vero costo delle dipendenze.&lt;/p&gt;

&lt;h2&gt;
  
  
  Le Due Vie dell'Inevitabilità (o: Perché Siamo Tutti Condannati)
&lt;/h2&gt;

&lt;p&gt;Quando aggiungiamo una dipendenza, fondamentalmente lo facciamo per due ragioni. E nessuna delle due è particolarmente confortante se ci pensi bene.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Prima ragione: non so come fare quella cosa.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Va bene, lo ammetto. Non so scrivere un parser HTTP sicuro. Non so implementare un sistema crittografico che non sia vulnerabile a timing attacks. Non so gestire la compressione di file senza perdere pezzi per strada. E quindi uso reqwest, uso ring, uso flate2.&lt;/p&gt;

&lt;p&gt;È una scelta saggia? Certo che sì. Solo un idiota cercherebbe di reinventare la crittografia. Ma ecco il punto: se non so come fare quella cosa, come faccio a debuggare quando quella cosa si rompe? Come faccio a capire se il problema è nel mio codice o nella dipendenza? Come faccio a valutare se quel panic che vedo è un bug loro o un uso scorretto mio?&lt;/p&gt;

&lt;p&gt;La risposta è: posso, ma solo fino a un certo punto, e il costo mentale sale vertiginosamente. Certo, posso leggere stack trace, testare input diversi, aprire issue su GitHub sperando che qualcuno risponda. Ma se il problema è veramente dentro quella dipendenza, devo comunque tuffarmi nel codice sorgente e cercare di capire cosa diavolo sta succedendo. E indovina quando potrei dover fare tutto questo? Esatto: alle 3 del pomeriggio di venerdì, con il cliente che urla e una deadline che si avvicina.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Seconda ragione: potrei farlo, ma non ho voglia.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;"Perché dovrei scrivere un generatore di UUID quando esiste già una crate per quello?"&lt;/p&gt;

&lt;p&gt;"Perché dovrei implementare un serializzatore JSON quando serde fa tutto così bene?"&lt;/p&gt;

&lt;p&gt;"Perché dovrei perdere tempo con un template engine quando posso usare tera?"&lt;/p&gt;

&lt;p&gt;Risposta breve: perché forse quel tempo "perso" ora ti avrebbe risparmiato una settimana di inferno dopo.&lt;/p&gt;

&lt;p&gt;Il paradosso è straordinario: eviti di scrivere qualcosa perché "ti ruberebbe troppo tempo", ma quando quella dipendenza si rompe, sei costretto a capirla lo stesso. Solo che ora lo devi fare:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Sotto pressione&lt;/li&gt;
&lt;li&gt;Con il cliente che ti bombarda di email&lt;/li&gt;
&lt;li&gt;Cercando di orientarti in un codice scritto da altri, con convenzioni diverse dalle tue&lt;/li&gt;
&lt;li&gt;Con la concreta possibilità che dovrai comunque riscrivere tutto da zero perché la dipendenza è abandonware o il maintainer non risponde&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Congratulazioni: hai risparmiato due giorni tre mesi fa per perderne sette adesso.&lt;/p&gt;

&lt;h2&gt;
  
  
  Il Vero Problema Non È la Dipendenza, Sei Tu
&lt;/h2&gt;

&lt;p&gt;Lo so, sembra duro. Ma lasciami spiegare.&lt;/p&gt;

&lt;p&gt;Il punto non è che usare dipendenze sia male. Il punto è che le trattiamo come soluzioni magiche invece che come quello che realmente sono: codice scritto da esseri umani fallibili che potrebbe esploderti in faccia in qualsiasi momento.&lt;/p&gt;

&lt;p&gt;Quante volte hai aggiunto una dipendenza senza nemmeno aprire il repository per vedere com'è fatto il codice? Quante volte hai guardato solo il numero di download su crates.io pensando "vabbè, se lo usano in tanti sarà affidabile"? Quante volte hai pensato "tanto se c'è un problema faccio un issue su GitHub e qualcuno lo fixerà"?&lt;/p&gt;

&lt;p&gt;Ecco, forse la vera incompetenza non è non sapere scrivere una libreria HTTP. Forse la vera incompetenza è delegare a sconosciuti su internet pezzi critici della nostra applicazione senza nemmeno sapere come funzionano.&lt;/p&gt;

&lt;p&gt;Quando aggiungi una dipendenza, non stai solo aggiungendo funzionalità. Stai aggiungendo:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Un punto di failure&lt;/strong&gt; che non controlli&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Una superficie d'attacco&lt;/strong&gt; per bug che non hai scritto tu&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Un debito di comprensione&lt;/strong&gt; che prima o poi dovrai pagare&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Una catena di dipendenze transitive&lt;/strong&gt; che potrebbero essere decine o centinaia&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Una responsabilità verso il tuo utente finale&lt;/strong&gt; che hai delegato a uno sconosciuto&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;E la cosa folle? Spesso non lo sappiamo nemmeno. Aggiungi una dipendenza pensando che sia "solo quella", ma in realtà stai portandoti dietro un intero ecosistema. Quel crate carino da 500 righe che hai aggiunto? Ha quindici dipendenze. Quelle quindici ne hanno altre trenta. E improvvisamente ti ritrovi con centinaia di migliaia di righe di codice di cui sei responsabile ma che non hai mai letto.&lt;/p&gt;

&lt;h2&gt;
  
  
  Supply Chain Attacks: Quando il Pericolo Viene da Dentro
&lt;/h2&gt;

&lt;p&gt;Parliamoci chiaro: quando aggiungi una dipendenza, stai letteralmente eseguendo codice scritto da uno sconosciuto su internet. Nella tua macchina. Con i tuoi permessi. Durante la compilazione, durante il runtime, sempre.&lt;/p&gt;

&lt;p&gt;E non sto parlando di scenari paranoici da film. Negli ultimi anni abbiamo visto di tutto: dipendenze microscopiche rimosse che hanno mandato in crash interi ecosistemi. Maintainer che, stufi di lavorare gratis per multinazionali miliardarie, hanno deliberatamente introdotto bug nei loro progetti come forma di protesta. Attaccanti che hanno preso il controllo di progetti legittimi e hanno iniettato malware per rubare credenziali o criptovalute.&lt;/p&gt;

&lt;p&gt;"Ma quello succede in altri linguaggi", dirai tu. "Noi in Rust siamo diversi, abbiamo il borrow checker, abbiamo la safety!"&lt;/p&gt;

&lt;p&gt;Certo. Il borrow checker ti protegge dai data race. Ma dimmi: ti protegge da un build.rs malevolo che, durante la compilazione, esfiltra le tue chiavi SSH? Ti protegge da una dipendenza che decide di mandare telemetria dei tuoi dati a un server sconosciuto? Ti protegge da un maintainer che, esausto dal lavoro non pagato, vende il controllo del progetto al miglior offerente senza dire niente a nessuno?&lt;/p&gt;

&lt;p&gt;La risposta è no. Il compilatore non può aiutarti se il problema non è il codice unsafe, ma le intenzioni di chi l'ha scritto.&lt;/p&gt;

&lt;p&gt;La supply chain del software è il Far West della sicurezza informatica. Ogni dipendenza è una porta aperta. E il bello (o il brutto, dipende dai punti di vista) è che spesso non ci pensiamo nemmeno. Aggiungiamo una crate perché "ha tante stelle su GitHub" o "tanti download su crates.io", come se la popolarità fosse garanzia di sicurezza o integrità.&lt;/p&gt;

&lt;p&gt;Ma la popolarità non ti dice nulla su chi mantiene quel progetto, su quanto sia motivato a continuare, su quanto sia resistente alla corruzione o alla stanchezza. Ogni dipendenza che aggiungi è un potenziale cavallo di Troia. E la cosa più spaventosa? Probabilmente non te ne accorgeresti nemmeno finché non è troppo tardi.&lt;/p&gt;

&lt;h2&gt;
  
  
  L'Abbandono: La Tragedia Silenziosa
&lt;/h2&gt;

&lt;p&gt;Poi c'è lo scenario più sottile e più comune: l'abbandono.&lt;/p&gt;

&lt;p&gt;Trovi una crate perfetta. Fa esattamente quello che ti serve. Il codice è pulito, i test passano, la documentazione è buona. La aggiungi al progetto. Tutto funziona. Per sei mesi, un anno, due anni.&lt;/p&gt;

&lt;p&gt;Poi un giorno apri una issue perché hai trovato un edge case. Nessuna risposta. Ne apri un'altra. Silenzio. Guardi la data dell'ultimo commit: tre anni fa. Guardi gli altri issue aperti: decine, tutti senza risposta.&lt;/p&gt;

&lt;p&gt;Il maintainer è sparito. Forse ha cambiato lavoro, forse ha perso interesse, forse è semplicemente bruciato dal dover mantenere gratis un progetto che usano migliaia di aziende che non contribuiscono mai.&lt;/p&gt;

&lt;p&gt;E ora? La community Rust ha iniziato a discutere di policy per le crate abbandonate, di come passare la manutenzione in modo più fluido, di come gestire questi casi. Ma sul campo, quando ti capita davvero, il risultato pratico è semplice: o forki il progetto e te lo mantieni da solo (con tutto il lavoro che comporta), o lo sostituisci (e buona fortuna a trovare qualcosa di compatibile), o lo riscrivi da zero (quello che avresti potuto fare dall'inizio, se solo non fossi stato "pigro").&lt;/p&gt;

&lt;p&gt;In ogni caso, sei TU che ti ritrovi a gestire il problema.&lt;/p&gt;

&lt;h2&gt;
  
  
  Il Patto Faustiano
&lt;/h2&gt;

&lt;p&gt;Mefistofele offre a Faust la conoscenza universale in cambio della sua anima. Le dipendenze ci offrono potenza immediata in cambio del nostro controllo futuro.&lt;/p&gt;

&lt;p&gt;È un deal che facciamo costantemente, spesso inconsapevolmente. Cargo add e via, abbiamo appena barattato due ore di sviluppo oggi contro potenziali giorni o settimane di debugging domani.&lt;/p&gt;

&lt;p&gt;Non sto dicendo che dovremmo smettere di usare dipendenze. Sarebbe stupido e controproducente. Ma sto dicendo che dovremmo smettere di trattarle come soluzioni gratuite e senza conseguenze.&lt;/p&gt;

&lt;p&gt;Ogni dipendenza ha un costo. Il fatto che questo costo non si manifesti immediatamente non significa che non esista. È come il debito con gli interessi: più lo ignori, più crescono.&lt;/p&gt;

&lt;h2&gt;
  
  
  Quindi? Che Facciamo?
&lt;/h2&gt;

&lt;p&gt;Non ho una soluzione magica. Se l'avessi, probabilmente la pacchettizzerei in una crate e la metterei su crates.io, creando una meta-dipendenza infinitamente ironica.&lt;/p&gt;

&lt;p&gt;Ma ho qualche pensiero:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Primo&lt;/strong&gt;: smetti di aggiungere dipendenze in automatico. Ogni volta che stai per scrivere cargo add, fermati e chiediti: "Ho davvero bisogno di questo? Potrei scriverlo io in tempo ragionevole? Se si rompe, sono almeno in grado di orientarmi nel codice per capire cosa sta succedendo?".&lt;/p&gt;

&lt;p&gt;Attenzione: non sto dicendo che devi saper reimplementare tutto. Ci sono dipendenze critiche - crypto, TLS, database driver, HTTP stack - che nessuno dovrebbe mai provare a scrivere da zero, ma che sono mantenute da team solidi, con auditing costante e community ampie. Il punto non è "se non puoi fixarla non usarla", ma "se nessuno nel team è in grado neanche di orientarsi in quel codice in caso di emergenza, forse la stai usando in modo troppo fiducioso".&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Secondo&lt;/strong&gt;: se aggiungi una dipendenza, aprila e leggila. Non tutta, non sei pazzo. Ma almeno i file principali, le API pubbliche, le decisioni architetturali fondamentali. Impiega un pomeriggio a capire come funziona. Quel pomeriggio potrebbe risparmiarti una settimana di inferno in futuro.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Terzo&lt;/strong&gt;: nel tuo team, ogni dipendenza dovrebbe avere un "owner mentale". Qualcuno che l'ha letta, che la capisce, che potrebbe forkare e patchare se necessario. Se nessuno vuole assumersi questa responsabilità, forse quella dipendenza è un problema.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Quarto&lt;/strong&gt;: preferisci dipendenze piccole, focalizzate, leggibili a mostri monolitici. In Rust siamo fortunati: l'ecosistema tende verso crate piccole e composibili. Sfrutta questa filosofia. Una dipendenza di 500 righe è infinitamente più gestibile di una di 50.000.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Quinto&lt;/strong&gt;: ricordati sempre che nel mondo Rust, dove il compilatore ci protegge da tanti errori, le dipendenze rimangono l'ultimo regno del caos. Il borrow checker non può aiutarti se il problema è in codice che non hai scritto tu e che non capisci.&lt;/p&gt;

&lt;h2&gt;
  
  
  La Vera Domanda
&lt;/h2&gt;

&lt;p&gt;Alla fine, la domanda non è "Posso evitare questa dipendenza?", ma "Sono disposto a pagare il prezzo quando verrà il momento?".&lt;/p&gt;

&lt;p&gt;Perché il momento arriverà. Forse tra un mese, forse tra un anno, forse tra cinque. Ma arriverà. E quando arriverà, sarai solo tu, il tuo codice, e un bug in mezzo a migliaia di righe scritte da qualcun altro.&lt;/p&gt;

&lt;p&gt;In quel momento, capirai il vero costo delle dipendenze. Non sono i megabyte di disco che occupano o i millisecondi in più di compilazione. È la perdita di controllo. È la delega di responsabilità. È il debito tecnico travestito da comodità.&lt;/p&gt;

&lt;p&gt;Ogni volta che aggiungi una dipendenza, stai facendo una scommessa: scommetti che il tempo che risparmi ora vale più del dolore potenziale futuro. A volte è una buona scommessa. Spesso no.&lt;/p&gt;

&lt;p&gt;Il progetto zero-dipendenze è un estremismo inutile. Ma il progetto che tira dentro tutto Crates.io "perché tanto è gratis" è altrettanto folle.&lt;/p&gt;

&lt;p&gt;La virtù sta nel mezzo consapevole. Nel riconoscere che ogni dipendenza è un patto faustiano, e nel decidere deliberatamente quali patti siamo disposti a fare.&lt;/p&gt;

&lt;p&gt;Perché alla fine, quando il tuo software esploderà (e lo farà, è solo questione di tempo), la domanda non sarà "Di chi è la colpa?". La domanda sarà "Tu sapevi cosa stavi importando?".&lt;/p&gt;

&lt;p&gt;E se la risposta è no, forse il problema non era la dipendenza.&lt;/p&gt;

&lt;p&gt;Eri tu.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;P.S.: Dopo aver scritto questo articolo, ho controllato le dipendenze del mio ultimo progetto. 6 dirette, 202 transitive. Non so nemmeno cosa facciano la metà di queste. Forse dovrei cominciare a praticare quello che predico. O forse no. Dopotutto, che potrebbe mai andare storto?&lt;/em&gt;&lt;/p&gt;

</description>
      <category>programming</category>
    </item>
    <item>
      <title>L'IA nella Programmazione: Strumento o Stampella?</title>
      <dc:creator>Marco Bollero</dc:creator>
      <pubDate>Sun, 18 Jan 2026 08:53:28 +0000</pubDate>
      <link>https://dev.to/marco_bollero_ba3c38ddd27/lia-nella-programmazione-strumento-o-stampella-ho2</link>
      <guid>https://dev.to/marco_bollero_ba3c38ddd27/lia-nella-programmazione-strumento-o-stampella-ho2</guid>
      <description>&lt;p&gt;Negli ultimi anni abbiamo assistito all'esplosione di strumenti di intelligenza artificiale per lo sviluppo software: GitHub Copilot, ChatGPT, Claude e tanti altri. Ma mentre questi strumenti diventano sempre più pervasivi, una domanda diventa urgente: li stiamo usando nel modo giusto? O stiamo crescendo una generazione di programmatori che sanno usare l'IA ma non sanno programmare?&lt;/p&gt;

&lt;p&gt;In questo articolo voglio condividere la mia visione su dove l'IA può essere un alleato prezioso e dove invece rischia di trasformarsi in una stampella che impedisce la crescita professionale.&lt;/p&gt;

&lt;h2&gt;
  
  
  Il Problema: L'Outsourcing del Pensiero
&lt;/h2&gt;

&lt;p&gt;Parliamoci chiaro: sempre più spesso osservo programmatori, soprattutto alle prime armi, che affrontano ogni problema copiando la richiesta in un'IA e incollando il codice risultante. Zero riflessione, zero comprensione, zero apprendimento. È come se stessimo assistendo a una sorta di "outsourcing del pensiero" – il problema non è più da risolvere, ma da delegare.&lt;/p&gt;

&lt;h3&gt;
  
  
  Un Problema Vecchio, ma Amplificato
&lt;/h3&gt;

&lt;p&gt;Questo problema non è nato con l'IA. Chi non ha mai copiato codice da StackOverflow senza capirlo completamente? Chi non ha mai preso una soluzione funzionante e l'ha incollata nel proprio progetto senza davvero comprendere perché la propria versione non funzionava?&lt;/p&gt;

&lt;p&gt;Il problema del "copia-incolla senza comprensione" esiste da quando esistono i forum di programmazione. La differenza cruciale è che allora c'erano dei &lt;strong&gt;"freni naturali"&lt;/strong&gt; incorporati nel processo.&lt;/p&gt;

&lt;p&gt;Quando cercavi su internet, dovevi:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Leggere thread di discussioni&lt;/li&gt;
&lt;li&gt;Capire il contesto del problema di qualcun altro&lt;/li&gt;
&lt;li&gt;Vedere la conversazione tra chi chiedeva e chi rispondeva&lt;/li&gt;
&lt;li&gt;Adattare manualmente il codice alla tua situazione specifica&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Anche se alla fine copiavi, c'era comunque un minimo di elaborazione cognitiva nel mezzo. Dovevi leggere, interpretare, adattare.&lt;/p&gt;

&lt;p&gt;Con l'IA, questo processo si è compresso a: scrivo la domanda, ricevo il codice perfettamente formattato per il mio caso specifico, lo incollo. Fine. Il ciclo è così rapido e fluido che bypassa completamente qualsiasi forma di riflessione.&lt;/p&gt;

&lt;p&gt;Inoltre, su StackOverflow trovavi non solo il codice, ma anche:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Spiegazioni del perché quella soluzione funzionava&lt;/li&gt;
&lt;li&gt;Discussioni nei commenti sui pro e contro&lt;/li&gt;
&lt;li&gt;Alternative proposte da altri utenti&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Era un ambiente che, anche involontariamente, incoraggiava l'apprendimento attraverso il confronto di idee. L'IA ti dà la risposta diretta, pulita, senza esporti al dibattito e alla complessità del ragionamento. È tremendamente più efficiente, ma anche tremendamente più pericolosa per chi sta imparando.&lt;/p&gt;

&lt;h3&gt;
  
  
  L'Analogia della Calcolatrice
&lt;/h3&gt;

&lt;p&gt;Immaginate un bambino alle elementari che deve imparare le addizioni. Se ogni volta che deve fare 7 + 5 prende la calcolatrice, cosa succede?&lt;/p&gt;

&lt;p&gt;Non imparerà mai a fare i calcoli mentalmente. Non svilupperà il senso del numero. Non capirà il ragionamento matematico sottostante. E quando si troverà in una situazione dove la calcolatrice non c'è, sarà completamente perso.&lt;/p&gt;

&lt;p&gt;La stessa cosa vale per la programmazione. Se ogni volta che devi implementare un algoritmo, risolvere un bug o strutturare un'applicazione chiedi all'IA, &lt;strong&gt;non stai sviluppando le competenze fondamentali del programmatore&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Copiare Senza Garanzie
&lt;/h3&gt;

&lt;p&gt;C'è un altro parallelo interessante: copiare il compito a scuola. Quando copi da qualcuno, non hai garanzia che quella soluzione sia corretta. Potresti star copiando da chi ne sa quanto te, o anche meno.&lt;/p&gt;

&lt;p&gt;Con l'IA è peggio: l'IA può generare codice che compila, che sembra funzionare, ma che nasconde bug sottili, vulnerabilità di sicurezza o inefficienze mostruose. Se non hai le competenze per capire quel codice, come fai a sapere se è buono o pessimo?&lt;/p&gt;

&lt;h3&gt;
  
  
  Cosa Perdiamo Veramente
&lt;/h3&gt;

&lt;p&gt;Quando deleghiamo il ragionamento all'IA, perdiamo tre cose fondamentali:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;La capacità di problem-solving&lt;/strong&gt;: Programmare non è solo scrivere sintassi corretta, è saper analizzare un problema, scomporlo, trovare soluzioni creative. Se l'IA pensa al posto tuo, non sviluppi mai questa abilità.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;L'originalità e la creatività&lt;/strong&gt;: Il codice dell'IA è, per definizione, una ricombinazione di pattern esistenti. Non può essere veramente innovativo. Se vuoi inventare soluzioni nuove a problemi vecchi, devi coltivare il tuo modo di pensare, la tua prospettiva unica.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;La capacità di debugging e manutenzione&lt;/strong&gt;: Questo è cruciale. Se non hai scritto tu il codice, se non lo capisci profondamente, come fai a debuggarlo quando inevitabilmente si rompe? Come lo ottimizzi? Come lo adatti quando i requisiti cambiano?&lt;/p&gt;

&lt;h2&gt;
  
  
  Gli Usi Corretti dell'IA
&lt;/h2&gt;

&lt;p&gt;Ora, attenzione: non sto dicendo che l'IA sia inutile o dannosa in assoluto. Anzi! Ci sono modi eccellenti di usare questi strumenti.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. L'IA come Tutor Personale
&lt;/h3&gt;

&lt;p&gt;L'IA può essere un tutor straordinario per l'apprendimento. Stai imparando un nuovo linguaggio? Chiedi all'IA di spiegarti i concetti, di mostrarti esempi, di chiarire le differenze tra approcci diversi.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Esempi pratici:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;"Spiegami la differenza tra una lista e una tupla in Python"&lt;/li&gt;
&lt;li&gt;"Come funziona il sistema dei trait in Rust?"&lt;/li&gt;
&lt;li&gt;"Quali sono i vantaggi del pattern Observer rispetto al pattern Publisher-Subscriber?"&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Qui l'IA non sta scrivendo codice per te, sta fungendo da insegnante. La differenza è sottile ma cruciale: stai usando l'IA per &lt;strong&gt;imparare a fare&lt;/strong&gt; qualcosa, non per &lt;strong&gt;farlo al posto tuo&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Comprendere Algoritmi Classici
&lt;/h3&gt;

&lt;p&gt;Vuoi capire come funziona il Quicksort? Chiedi all'IA di spiegartelo passo passo, magari con un esempio visivo. Questo è apprendimento attivo, non delega passiva.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Supporto nella Documentazione
&lt;/h3&gt;

&lt;p&gt;Hai scritto tu un pezzo di codice complesso e vuoi documentarlo bene? L'IA può aiutarti a strutturare la documentazione, suggerire cosa includere, persino generare i commenti di base che poi tu rifinisci.&lt;/p&gt;

&lt;p&gt;Qui il lavoro intellettuale l'hai fatto tu, l'IA ti sta solo aiutando nella parte "noiosa" del processo.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Generazione di Test
&lt;/h3&gt;

&lt;p&gt;Hai implementato una funzione e vuoi testarla a fondo? Chiedi all'IA di generare casi di test, inclusi edge cases che potresti non aver considerato.&lt;/p&gt;

&lt;p&gt;Anche qui: tu hai scritto il codice, capisci cosa fa, e stai usando l'IA per una verifica più completa. Il codice di produzione resta frutto del tuo ragionamento.&lt;/p&gt;

&lt;h3&gt;
  
  
  La Regola d'Oro
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Usa l'IA per imparare, capire, verificare, documentare. Non usarla per sostituire il tuo pensiero critico e la tua capacità di risolvere problemi.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;L'IA dovrebbe essere come un libro di testo avanzato, non come un compagno di classe a cui copiare i compiti.&lt;/p&gt;

&lt;h2&gt;
  
  
  Le Questioni Legali ed Etiche
&lt;/h2&gt;

&lt;p&gt;C'è un aspetto che molti sottovalutano, ma che è fondamentale: le questioni legali e di licenze.&lt;/p&gt;

&lt;h3&gt;
  
  
  Il Problema delle Licenze
&lt;/h3&gt;

&lt;p&gt;Le IA generative sono state addestrate su enormi quantità di codice disponibile su internet. Molto di questo codice è open source, con licenze specifiche come GPL, MIT, Apache e così via.&lt;/p&gt;

&lt;p&gt;La domanda da un milione di dollari è: &lt;strong&gt;quando un'IA genera codice ispirandosi a codice con cui è stata addestrata, quel codice nuovo è da considerarsi "derivato" dal codice originale?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Se la risposta è sì, ci sono problemi. Le licenze copyleft come la GPL richiedono che il codice derivato mantenga la stessa licenza. Questo significa che se usi codice generato da un'IA addestrata su codice GPL, potresti essere obbligato a rilasciare il tuo intero progetto con licenza GPL.&lt;/p&gt;

&lt;h3&gt;
  
  
  Una Zona Grigia Normativa
&lt;/h3&gt;

&lt;p&gt;Al momento, questa è una zona grigia. Ci sono cause legali in corso, e il quadro normativo è in evoluzione. Diverse aziende hanno già vietato l'uso di IA generative per il codice di produzione proprio per questi rischi.&lt;/p&gt;

&lt;p&gt;Se lavorate per un'azienda e generate codice con un'IA, state potenzialmente introducendo rischi legali enormi. L'azienda potrebbe trovarsi esposta a contenziosi per violazione di copyright o licenze.&lt;/p&gt;

&lt;p&gt;E non sto nemmeno parlando dei casi (rari ma documentati) in cui l'IA riproduce quasi letteralmente pezzi di codice del suo training set, magari inclusi commenti e nomi di variabili originali. In quei casi non c'è dubbio: è una copia diretta.&lt;/p&gt;

&lt;h3&gt;
  
  
  L'Etica della Formazione Professionale
&lt;/h3&gt;

&lt;p&gt;C'è anche una questione etica più ampia: come comunità, abbiamo la responsabilità di formare programmatori competenti. Se normalizziamo l'uso dell'IA come sostituto del ragionamento, stiamo danneggiando la qualità complessiva della professione.&lt;/p&gt;

&lt;h2&gt;
  
  
  Verso una Visione Equilibrata
&lt;/h2&gt;

&lt;p&gt;L'IA non sparirà. Anzi, diventerà sempre più pervasiva. E non è nemmeno desiderabile eliminarla completamente dagli strumenti di sviluppo. Il punto è &lt;strong&gt;trovare il giusto equilibrio&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Quattro Principi Guida
&lt;/h3&gt;

&lt;p&gt;Ecco la mia proposta di linee guida per un uso responsabile dell'IA:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Primo principio – Impara prima le basi senza IA&lt;/strong&gt;: Se stai iniziando, se stai imparando un nuovo linguaggio o paradigma, fallo senza assistenza AI. Sporca le mani, sbaglia, debugga, soffri un po'. È così che si impara davvero.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Secondo principio – Usa l'IA per accelerare, non per sostituire&lt;/strong&gt;: Una volta che sai fare qualcosa, l'IA può aiutarti a farlo più velocemente. Ma la comprensione deve venire prima.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Terzo principio – Verifica sempre&lt;/strong&gt;: Mai, e ripeto mai, copiare codice dall'IA senza capirlo completamente. Leggilo, analizzalo, testalo, verifica che faccia esattamente quello che deve fare.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Quarto principio – L'IA come amplificatore di competenza&lt;/strong&gt;: Più sei bravo, più valore puoi estrarre dall'IA. Un programmatore esperto usa l'IA in modo chirurgico per compiti specifici. Un principiante che delega tutto all'IA resta un principiante per sempre.&lt;/p&gt;

&lt;h3&gt;
  
  
  Il Mio Workflow Personale
&lt;/h3&gt;

&lt;p&gt;Vi racconto come uso io l'IA nel mio lavoro quotidiano:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cosa faccio:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Lo uso per esplorare API o librerie nuove: "Come si usa questa funzione?" o "Mostrami un esempio di configurazione"&lt;/li&gt;
&lt;li&gt;Lo uso per brainstorming architetturale: "Quali sono i pro e contro di questo approccio?" (ma la decisione finale è sempre mia)&lt;/li&gt;
&lt;li&gt;Lo uso per generare test di base, che poi espando e raffino manualmente&lt;/li&gt;
&lt;li&gt;Lo uso per la documentazione, ma solo dopo che il codice è scritto e funzionante&lt;/li&gt;
&lt;li&gt;Se mi serve un algoritmo classico, chiedo lo pseudocodice o una descrizione del funzionamento, non l'implementazione completa. In questo modo la "trasformazione" in codice reale nel mio contesto specifico resta sotto il mio controllo&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Cosa NON faccio:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Non uso l'IA per scrivere la logica core dell'applicazione&lt;/li&gt;
&lt;li&gt;Non uso l'IA per risolvere bug complessi&lt;/li&gt;
&lt;li&gt;Non uso l'IA per implementare algoritmi che dovrei conoscere&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  La Competenza è Insostituibile
&lt;/h3&gt;

&lt;p&gt;Ricordate: &lt;strong&gt;l'IA è uno strumento potentissimo, ma è solo uno strumento&lt;/strong&gt;. La competenza, la comprensione profonda, la capacità di pensare in modo critico e creativo – queste cose possono venire solo dall'esperienza, dallo studio, dall'errore e correzione.&lt;/p&gt;

&lt;p&gt;Non c'è scorciatoia per diventare un bravo programmatore.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusione
&lt;/h2&gt;

&lt;p&gt;L'IA nella programmazione può essere un alleato prezioso se usata per imparare, approfondire, verificare e documentare. Diventa un problema quando sostituisce il tuo pensiero critico e ti impedisce di sviluppare competenze reali.&lt;/p&gt;

&lt;p&gt;Il mio appello, soprattutto a chi sta iniziando: &lt;strong&gt;non abbiate fretta&lt;/strong&gt;. La programmazione è un'abilità che si costruisce con il tempo, con la pratica deliberata, con gli errori. Ogni problema che risolvete da soli è un mattoncino che aggiungete alle vostre competenze.&lt;/p&gt;

&lt;p&gt;L'IA sarà sempre lì, pronta ad aiutarvi. Ma prima dovete essere voi a sapere dove state andando.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>development</category>
    </item>
    <item>
      <title>Guida Completa: Neovim 0.11 IDE per Rust su Ubuntu/MacOS</title>
      <dc:creator>Marco Bollero</dc:creator>
      <pubDate>Wed, 15 Oct 2025 13:37:04 +0000</pubDate>
      <link>https://dev.to/marco_bollero_ba3c38ddd27/guida-completa-neovim-011-ide-per-rust-su-ubuntumacos-5emf</link>
      <guid>https://dev.to/marco_bollero_ba3c38ddd27/guida-completa-neovim-011-ide-per-rust-su-ubuntumacos-5emf</guid>
      <description>&lt;p&gt;Benvenuto in questa guida completa all'installazione e alla configurazione di Neovim 0.11 per lo sviluppo in Rust! 🦀&lt;/p&gt;

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

&lt;p&gt;Se sei uno sviluppatore Rust alla ricerca di un editor di testo che sia allo stesso tempo leggero, veloce e incredibilmente personalizzabile, Neovim è la scelta perfetta. Dimentica i pesanti IDE tradizionali: con questa guida, trasformeremo Neovim in un ambiente di sviluppo Rust moderno e produttivo, su misura per le tue esigenze.&lt;/p&gt;

&lt;p&gt;In questa guida vedremo come:&lt;/p&gt;

&lt;p&gt;Installare l'ultima versione di Neovim (0.11).&lt;/p&gt;

&lt;p&gt;Configurare da zero un ambiente di sviluppo minimale utilizzando Lua.&lt;/p&gt;

&lt;p&gt;Integrare rust-analyzer tramite il Language Server Protocol (LSP) nativo di Neovim per ottenere funzionalità da IDE come l'autocompletamento, la diagnostica in tempo reale e la navigazione del codice.&lt;/p&gt;

&lt;p&gt;Impostare il syntax highlighting con Tree-sitter per un'analisi del codice più precisa e veloce.&lt;/p&gt;

&lt;p&gt;Alla fine di questo percorso, avrai una configurazione Neovim funzionale e performante, pronta per affrontare qualsiasi progetto Rust. Iniziamo!&lt;/p&gt;

&lt;p&gt;PS - Altrimenti puoi semplicemente eseguire questi comandi:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; &lt;span class="nv"&gt;$HOME&lt;/span&gt;/.config/
&lt;span class="nb"&gt;mv &lt;/span&gt;nvim nvim.bkp_ &lt;span class="c"&gt;# Crea backup configurazione corrente&lt;/span&gt;
git clone git@github.com:marc0x71/nvim_config_rust.git nvim
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;e avrai tutto già installato e pronto all'uso! 🤗🦀&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisiti e Dipendenze di Sistema
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Installazione su GNU/Linux (Ubuntu)
&lt;/h3&gt;

&lt;p&gt;Prima di iniziare, installiamo tutte le dipendenze necessarie:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Aggiorna il sistema&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt update &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;sudo &lt;/span&gt;apt upgrade &lt;span class="nt"&gt;-y&lt;/span&gt;

&lt;span class="c"&gt;# Dipendenze per i plugin&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; ripgrep fd-find

&lt;span class="c"&gt;# Build essentials (necessari per compilare parser Treesitter e alcune estensioni Rust)&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; build-essential git curl

&lt;span class="c"&gt;# Node.js (opzionale, necessario solo per alcuni LSP non-Rust)&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; nodejs

&lt;span class="c"&gt;# Creiamo un symlink per fd (su Ubuntu si chiama fdfind)&lt;/span&gt;
&lt;span class="nb"&gt;sudo ln&lt;/span&gt; &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="si"&gt;$(&lt;/span&gt;which fdfind&lt;span class="si"&gt;)&lt;/span&gt; /usr/local/bin/fd 2&amp;gt;/dev/null &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  MacOS
&lt;/h3&gt;

&lt;p&gt;Su macOS useremo Homebrew come package manager:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Installa Homebrew se non già installato&lt;/span&gt;
/bin/bash &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;curl &lt;span class="nt"&gt;-fsSL&lt;/span&gt; https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

&lt;span class="c"&gt;# Installa Xcode Command Line Tools (contiene gcc, git, etc.)&lt;/span&gt;
xcode-select &lt;span class="nt"&gt;--install&lt;/span&gt;

&lt;span class="c"&gt;# Dipendenze per i plugin&lt;/span&gt;
brew &lt;span class="nb"&gt;install &lt;/span&gt;ripgrep fd

&lt;span class="c"&gt;# Node.js (opzionale, utile per altri linguaggi)&lt;/span&gt;
brew &lt;span class="nb"&gt;install &lt;/span&gt;node
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Spiegazione delle dipendenze:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;ripgrep&lt;/strong&gt;: ricerca velocissima nei file, usata da Telescope&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;fd&lt;/strong&gt;: alternativa moderna a &lt;code&gt;find&lt;/code&gt;, usata da Telescope&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;build-essential&lt;/strong&gt;: gcc e g++ necessari per compilare i parser Treesitter&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Node.js&lt;/strong&gt;: opzionale, ma utile se userai altri linguaggi oltre a Rust&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Installazione di Neovim 0.11
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Installazione su MacOS
&lt;/h3&gt;

&lt;p&gt;Per eseguire l'installazione di NeoVim, basterà:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;h3&gt;
  
  
  Installazione su GNU/Linux (Ubuntu)
&lt;/h3&gt;

&lt;p&gt;Per questa guida prendiamo come riferimento la distribuzione GNU/Linux Ubuntu.&lt;/p&gt;

&lt;p&gt;Installiamo Neovim tramite snap:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Installa Neovim 0.11 tramite snap (flag --classic per accesso completo al sistema)&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;snap &lt;span class="nb"&gt;install &lt;/span&gt;nvim &lt;span class="nt"&gt;--classic&lt;/span&gt;

&lt;span class="c"&gt;# Verifichiamo l'installazione&lt;/span&gt;
nvim &lt;span class="nt"&gt;--version&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Dovresti vedere output simile a:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;NVIM v0.11.4
Build type: Release
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Perché usare snap?&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✅ Installazione rapida (pochi secondi vs 10-15 minuti di compilazione)&lt;/li&gt;
&lt;li&gt;✅ Sempre aggiornato al latest stable&lt;/li&gt;
&lt;li&gt;✅ Aggiornamenti automatici gestiti da snap&lt;/li&gt;
&lt;li&gt;✅ Nessuna dipendenza di build necessaria&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Nota&lt;/strong&gt;: Il flag &lt;code&gt;--classic&lt;/code&gt; è necessario perché Neovim deve accedere liberamente ai file del sistema per funzionare come editor.&lt;/p&gt;

&lt;h3&gt;
  
  
  Metodo alternativo: Compilazione dai sorgenti
&lt;/h3&gt;

&lt;p&gt;Se preferisci compilare dai sorgenti per avere il controllo completo, su Ubuntu ti servirà:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Installa dipendenze di build&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; ninja-build gettext cmake unzip
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;mentre su MacOS:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Installa dipendenze di build&lt;/span&gt;
brew &lt;span class="nb"&gt;install &lt;/span&gt;ninja cmake gettext
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Possiamo ora compilare NeoVim per il nostro sistema:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Scarica e compila&lt;/span&gt;
&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; ~/build &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;cd&lt;/span&gt; ~/build
git clone https://github.com/neovim/neovim.git
&lt;span class="nb"&gt;cd &lt;/span&gt;neovim
git checkout v0.11.4
make &lt;span class="nv"&gt;CMAKE_BUILD_TYPE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;Release
&lt;span class="nb"&gt;sudo &lt;/span&gt;make &lt;span class="nb"&gt;install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Pro: Controllo totale sulla versione e opzioni di build&lt;br&gt;&lt;br&gt;
Contro: Richiede 10-15 minuti e più dipendenze&lt;/p&gt;


&lt;h2&gt;
  
  
  Installazione Toolchain Rust
&lt;/h2&gt;

&lt;p&gt;Installiamo Rust e i componenti necessari per lo sviluppo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Installa rustup (gestore della toolchain Rust)&lt;/span&gt;
curl &lt;span class="nt"&gt;--proto&lt;/span&gt; &lt;span class="s1"&gt;'=https'&lt;/span&gt; &lt;span class="nt"&gt;--tlsv1&lt;/span&gt;.2 &lt;span class="nt"&gt;-sSf&lt;/span&gt; https://sh.rustup.rs | sh

&lt;span class="c"&gt;# Ricarichiamo il PATH&lt;/span&gt;
&lt;span class="nb"&gt;source&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$HOME&lt;/span&gt;&lt;span class="s2"&gt;/.cargo/env"&lt;/span&gt;

&lt;span class="c"&gt;# Installiamo i componenti necessari se non precedentemente installati&lt;/span&gt;
rustup component add rust-analyzer  &lt;span class="c"&gt;# LSP per Rust&lt;/span&gt;
rustup component add rustfmt         &lt;span class="c"&gt;# Formatter&lt;/span&gt;
rustup component add clippy          &lt;span class="c"&gt;# Linter&lt;/span&gt;

&lt;span class="c"&gt;# Verifichiamo l'installazione&lt;/span&gt;
rustc &lt;span class="nt"&gt;--version&lt;/span&gt;
cargo &lt;span class="nt"&gt;--version&lt;/span&gt;
rust-analyzer &lt;span class="nt"&gt;--version&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Nota importante&lt;/strong&gt;: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;rust-analyzer&lt;/code&gt; è il language server che fornisce autocompletamento, diagnostica e altre funzionalità IDE (LSP)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;codelldb&lt;/strong&gt; (debugger) verrà installato automaticamente tramite Mason (plugin di Neovim) nella sezione successiva&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Struttura della Configurazione
&lt;/h2&gt;

&lt;p&gt;Creiamo la struttura delle directory per la configurazione di Neovim:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; ~/.config/nvim/lua/plugins
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;La struttura finale sarà:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;~/.config/nvim/
├── init.lua                 # File principale
└── lua/
    └── plugins/
        ├── mason.lua        # Config Mason (package manager)
        ├── cmp.lua          # Config nvim-cmp (autocompletamento)
        ├── treesitter.lua   # Config Treesitter
        ├── telescope.lua    # Config Telescope
        ├── oil.lua          # Config Oil
        ├── rustacean.lua    # Config Rustaceanvim
        ├── gitsigns.lua     # Config Gitsigns (Git integration)
        ├── fugitive.lua     # Config Fugitive (Git commands)
        ├── which-key.lua    # Config Which-Key (keybinding hints)
        ├── trouble.lua      # Config Trouble (diagnostics list)
        ├── fidget.lua       # Config Fidget (LSP notifications)
        ├── lualine.lua      # Config Lualine (statusline)
        └── colorscheme.lua  # Config Gruvbox Material
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Configurazione Lazy.nvim
&lt;/h2&gt;

&lt;p&gt;Creiamo il file &lt;code&gt;~/.config/nvim/init.lua&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight lua"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- init.lua&lt;/span&gt;
&lt;span class="c1"&gt;-- Configurazione base di Neovim&lt;/span&gt;

&lt;span class="c1"&gt;-- Opzioni generali&lt;/span&gt;
&lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mapleader&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;" "&lt;/span&gt;  &lt;span class="c1"&gt;-- Space come leader key&lt;/span&gt;
&lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;maplocalleader&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;" "&lt;/span&gt;

&lt;span class="c1"&gt;-- Impostazioni UI&lt;/span&gt;
&lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;opt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;number&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;          &lt;span class="c1"&gt;-- Numeri di riga&lt;/span&gt;
&lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;opt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;relativenumber&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;  &lt;span class="c1"&gt;-- Numeri relativi&lt;/span&gt;
&lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;opt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mouse&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'a'&lt;/span&gt;            &lt;span class="c1"&gt;-- Abilita mouse&lt;/span&gt;
&lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;opt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ignorecase&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;      &lt;span class="c1"&gt;-- Ignora case nella ricerca&lt;/span&gt;
&lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;opt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;smartcase&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;       &lt;span class="c1"&gt;-- Case-sensitive se maiuscole presenti&lt;/span&gt;
&lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;opt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;hlsearch&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;       &lt;span class="c1"&gt;-- Non evidenziare ricerche&lt;/span&gt;
&lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;opt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;wrap&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;           &lt;span class="c1"&gt;-- Non wrappare le righe&lt;/span&gt;
&lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;opt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;breakindent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;     &lt;span class="c1"&gt;-- Mantieni indentazione quando wrapped&lt;/span&gt;
&lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;opt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tabstop&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;            &lt;span class="c1"&gt;-- Tab = 4 spazi&lt;/span&gt;
&lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;opt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;shiftwidth&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;         &lt;span class="c1"&gt;-- Indentazione = 4 spazi&lt;/span&gt;
&lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;opt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;expandtab&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;       &lt;span class="c1"&gt;-- Usa spazi invece di tab&lt;/span&gt;
&lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;opt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;termguicolors&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;   &lt;span class="c1"&gt;-- Abilita colori 24-bit&lt;/span&gt;

&lt;span class="c1"&gt;-- Clipboard di sistema&lt;/span&gt;
&lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;opt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;clipboard&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'unnamedplus'&lt;/span&gt;

&lt;span class="c1"&gt;-- Salvataggio automatico undo&lt;/span&gt;
&lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;opt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;undofile&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;

&lt;span class="c1"&gt;-- Tempo di aggiornamento ridotto&lt;/span&gt;
&lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;opt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;updatetime&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;250&lt;/span&gt;
&lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;opt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;signcolumn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'yes'&lt;/span&gt;

&lt;span class="c1"&gt;-- Bootstrap lazy.nvim&lt;/span&gt;
&lt;span class="kd"&gt;local&lt;/span&gt; &lt;span class="n"&gt;lazypath&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stdpath&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"data"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;..&lt;/span&gt; &lt;span class="s2"&gt;"/lazy/lazy.nvim"&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;loop&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fs_stat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lazypath&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
  &lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;system&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="s2"&gt;"git"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s2"&gt;"clone"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s2"&gt;"--filter=blob:none"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s2"&gt;"https://github.com/folke/lazy.nvim.git"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s2"&gt;"--branch=stable"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;lazypath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;opt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rtp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;prepend&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lazypath&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;-- Setup lazy.nvim con i plugin&lt;/span&gt;
&lt;span class="nb"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"lazy"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;setup&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="c1"&gt;-- Importa tutti i file dalla directory plugins&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;import&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"plugins"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;checker&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;enabled&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="c1"&gt;-- Controlla automaticamente aggiornamenti&lt;/span&gt;
    &lt;span class="n"&gt;notify&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="c1"&gt;-- Non notificare&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="n"&gt;change_detection&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;notify&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="c1"&gt;-- Non notificare cambiamenti config&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="c1"&gt;-- Toggle diagnostics&lt;/span&gt;
&lt;span class="kd"&gt;local&lt;/span&gt; &lt;span class="n"&gt;diagnostics_active&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="kd"&gt;local&lt;/span&gt; &lt;span class="n"&gt;toggle_diagnostics&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="n"&gt;diagnostics_active&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;diagnostics_active&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;diagnostics_active&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
    &lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;nvim_echo&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s2"&gt;"Show diagnostics"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{})&lt;/span&gt;
    &lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;diagnostic&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;enable&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;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;nvim_echo&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s2"&gt;"Disable diagnostics"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{})&lt;/span&gt;
    &lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;diagnostic&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;enable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="kd"&gt;local&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;open_terminal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;command&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;command&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;command&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="nb"&gt;os.getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"SHELL"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;os.getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"TMUX"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;os.getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"POETRY_ACTIVE"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
      &lt;span class="n"&gt;command&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"poetry run "&lt;/span&gt; &lt;span class="o"&gt;..&lt;/span&gt; &lt;span class="n"&gt;command&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
    &lt;span class="c1"&gt;--  TMUX session active&lt;/span&gt;
    &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"silent !tmux split-window -l 10 "&lt;/span&gt; &lt;span class="o"&gt;..&lt;/span&gt; &lt;span class="n"&gt;command&lt;/span&gt; &lt;span class="o"&gt;..&lt;/span&gt; &lt;span class="s2"&gt;"&amp;lt;cr&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cmd&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"silent !tmux split-window -l 10 "&lt;/span&gt; &lt;span class="o"&gt;..&lt;/span&gt; &lt;span class="n"&gt;command&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;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cmd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;vnew&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cmd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;term&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;command&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cmd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;wincmd&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"J"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;nvim_win_set_height&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="c1"&gt;-- Keymaps generali&lt;/span&gt;
&lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;keymap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'n'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'&amp;lt;leader&amp;gt;w'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'&amp;lt;cmd&amp;gt;write&amp;lt;cr&amp;gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;desc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Save'&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;keymap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'n'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'&amp;lt;leader&amp;gt;q'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'&amp;lt;cmd&amp;gt;quit&amp;lt;cr&amp;gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;desc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Quit'&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;keymap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"n"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&amp;lt;M-n&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&amp;lt;cmd&amp;gt;bnext&amp;lt;CR&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{})&lt;/span&gt;
&lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;keymap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"n"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&amp;lt;M-p&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&amp;lt;cmd&amp;gt;bprev&amp;lt;CR&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{})&lt;/span&gt;
&lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;keymap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"n"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&amp;lt;Esc&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&amp;lt;cmd&amp;gt;nohlsearch&amp;lt;CR&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;keymap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"t"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&amp;lt;esc&amp;gt;&amp;lt;esc&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&amp;lt;c-\\&amp;gt;&amp;lt;c-n&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{})&lt;/span&gt;

&lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;keymap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"n"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&amp;lt;leader&amp;gt;tt"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="n"&gt;open_terminal&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;desc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"[T]erminal "&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;


&lt;span class="c1"&gt;-- Keymaps per diagnostics&lt;/span&gt;
&lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;keymap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'n'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'[d'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;diagnostic&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;goto_prev&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;desc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Previous diagnostic'&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;keymap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'n'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;']d'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;diagnostic&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;goto_next&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;desc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Next diagnostic'&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;keymap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'n'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'&amp;lt;leader&amp;gt;e'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;diagnostic&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;open_float&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;desc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Show diagnostic error'&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;keymap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"n"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&amp;lt;leader&amp;gt;xi"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;toggle_diagnostics&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;desc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Toggle [i]nline diagnostic"&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Spiegazione keymaps diagnostics:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;&amp;lt;leader&amp;gt;e&lt;/code&gt; (Space + e) mostra popup con errore/warning della riga corrente&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;&amp;lt;leader&amp;gt;xi&lt;/code&gt; (Space + xi) abilita/disabilita la visualizzazione degli errori/warning&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;]d&lt;/code&gt; salta al prossimo diagnostic (errore/warning)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;[d&lt;/code&gt; salta al diagnostic precedente&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  Mason (&lt;code&gt;~/.config/nvim/lua/plugins/mason.lua&lt;/code&gt;)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight lua"&gt;&lt;code&gt;&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="s2"&gt;"williamboman/mason.nvim"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;dependencies&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="s2"&gt;"williamboman/mason-lspconfig.nvim"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s2"&gt;"jay-babu/mason-nvim-dap.nvim"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="n"&gt;config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="kd"&gt;local&lt;/span&gt; &lt;span class="n"&gt;mason&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"mason"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;local&lt;/span&gt; &lt;span class="n"&gt;mason_lspconfig&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"mason-lspconfig"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;local&lt;/span&gt; &lt;span class="n"&gt;mason_nvim_dap&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"mason-nvim-dap"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;-- Setup Mason&lt;/span&gt;
    &lt;span class="n"&gt;mason&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setup&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="n"&gt;ui&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;icons&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="n"&gt;package_installed&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="n"&gt;package_pending&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="n"&gt;package_uninstalled&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="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;

    &lt;span class="c1"&gt;-- Setup Mason LSPConfig&lt;/span&gt;
    &lt;span class="n"&gt;mason_lspconfig&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setup&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="c1"&gt;-- Questa lista è vuota perché per Rust usiamo rustaceanvim&lt;/span&gt;
      &lt;span class="c1"&gt;-- che gestisce rust-analyzer automaticamente&lt;/span&gt;
      &lt;span class="n"&gt;ensure_installed&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;-- Setup Mason DAP - installa automaticamente codelldb&lt;/span&gt;
    &lt;span class="n"&gt;mason_nvim_dap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setup&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="n"&gt;ensure_installed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s2"&gt;"codelldb"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="n"&gt;automatic_installation&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="c1"&gt;-- Keymap per aprire Mason&lt;/span&gt;
    &lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;keymap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'n'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'&amp;lt;leader&amp;gt;m'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'&amp;lt;cmd&amp;gt;Mason&amp;lt;cr&amp;gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;desc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Open Mason'&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Spiegazione&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Mason è un package manager per Neovim che gestisce LSP servers, DAP adapters, linters e formatters&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;mason-nvim-dap&lt;/code&gt; installa &lt;strong&gt;automaticamente&lt;/strong&gt; codelldb al primo avvio&lt;/li&gt;
&lt;li&gt;Non includiamo rust-analyzer qui perché rustaceanvim lo usa direttamente dal sistema&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  nvim-cmp (&lt;code&gt;~/.config/nvim/lua/plugins/cmp.lua&lt;/code&gt;)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight lua"&gt;&lt;code&gt;&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="s2"&gt;"hrsh7th/nvim-cmp"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;event&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"InsertEnter"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;dependencies&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;-- Snippet Engine&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="s2"&gt;"L3MON4D3/LuaSnip"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="n"&gt;version&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"v2.*"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="n"&gt;build&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"make install_jsregexp"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;

    &lt;span class="c1"&gt;-- Autocompletion sources&lt;/span&gt;
    &lt;span class="s2"&gt;"saadparwaiz1/cmp_luasnip"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;     &lt;span class="c1"&gt;-- Snippet completions&lt;/span&gt;
    &lt;span class="s2"&gt;"hrsh7th/cmp-nvim-lsp"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;         &lt;span class="c1"&gt;-- LSP completions&lt;/span&gt;
    &lt;span class="s2"&gt;"hrsh7th/cmp-buffer"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;           &lt;span class="c1"&gt;-- Buffer completions&lt;/span&gt;
    &lt;span class="s2"&gt;"hrsh7th/cmp-path"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;             &lt;span class="c1"&gt;-- Path completions&lt;/span&gt;
    &lt;span class="s2"&gt;"hrsh7th/cmp-nvim-lua"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;         &lt;span class="c1"&gt;-- Neovim Lua API completions&lt;/span&gt;

    &lt;span class="c1"&gt;-- Snippet collection (optional)&lt;/span&gt;
    &lt;span class="s2"&gt;"rafamadriz/friendly-snippets"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="n"&gt;config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="kd"&gt;local&lt;/span&gt; &lt;span class="n"&gt;cmp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"cmp"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;local&lt;/span&gt; &lt;span class="n"&gt;luasnip&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"luasnip"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;-- Carica snippet da friendly-snippets&lt;/span&gt;
    &lt;span class="nb"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"luasnip.loaders.from_vscode"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;lazy_load&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="n"&gt;cmp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setup&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="n"&gt;snippet&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;expand&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
          &lt;span class="n"&gt;luasnip&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;lsp_expand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;

      &lt;span class="n"&gt;mapping&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cmp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mapping&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;preset&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;insert&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&amp;lt;C-k&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cmp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mapping&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;select_prev_item&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="c1"&gt;-- Seleziona precedente&lt;/span&gt;
        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&amp;lt;C-j&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cmp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mapping&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;select_next_item&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="c1"&gt;-- Seleziona successivo&lt;/span&gt;
        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&amp;lt;C-b&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cmp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mapping&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;scroll_docs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&amp;lt;C-f&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cmp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mapping&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;scroll_docs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&amp;lt;C-Space&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cmp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mapping&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;complete&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;     &lt;span class="c1"&gt;-- Mostra completamento&lt;/span&gt;
        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&amp;lt;C-e&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cmp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mapping&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;abort&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;            &lt;span class="c1"&gt;-- Chiudi&lt;/span&gt;
        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&amp;lt;CR&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cmp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mapping&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;confirm&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nb"&gt;select&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="p"&gt;}),&lt;/span&gt; &lt;span class="c1"&gt;-- Conferma selezione&lt;/span&gt;

        &lt;span class="c1"&gt;-- Tab per navigare snippet&lt;/span&gt;
        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&amp;lt;Tab&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cmp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mapping&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fallback&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
          &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;cmp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;visible&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
            &lt;span class="n"&gt;cmp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;select_next_item&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
          &lt;span class="k"&gt;elseif&lt;/span&gt; &lt;span class="n"&gt;luasnip&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;expand_or_jumpable&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
            &lt;span class="n"&gt;luasnip&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;expand_or_jump&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;fallback&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
          &lt;span class="k"&gt;end&lt;/span&gt;
        &lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s2"&gt;"i"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"s"&lt;/span&gt; &lt;span class="p"&gt;}),&lt;/span&gt;

        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&amp;lt;S-Tab&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cmp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mapping&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fallback&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
          &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;cmp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;visible&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
            &lt;span class="n"&gt;cmp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;select_prev_item&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
          &lt;span class="k"&gt;elseif&lt;/span&gt; &lt;span class="n"&gt;luasnip&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;jumpable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
            &lt;span class="n"&gt;luasnip&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;jump&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&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;fallback&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
          &lt;span class="k"&gt;end&lt;/span&gt;
        &lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s2"&gt;"i"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"s"&lt;/span&gt; &lt;span class="p"&gt;}),&lt;/span&gt;
      &lt;span class="p"&gt;}),&lt;/span&gt;

      &lt;span class="c1"&gt;-- Sources per autocompletamento (ordine = priorità)&lt;/span&gt;
      &lt;span class="n"&gt;sources&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cmp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sources&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"nvim_lsp"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;   &lt;span class="c1"&gt;-- Da LSP&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"luasnip"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;    &lt;span class="c1"&gt;-- Da snippet&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"buffer"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;     &lt;span class="c1"&gt;-- Da buffer corrente&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"path"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;       &lt;span class="c1"&gt;-- Da filesystem&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"nvim_lua"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;   &lt;span class="c1"&gt;-- Da Neovim Lua API&lt;/span&gt;
      &lt;span class="p"&gt;}),&lt;/span&gt;

      &lt;span class="c1"&gt;-- Formattazione voci completamento&lt;/span&gt;
      &lt;span class="n"&gt;formatting&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;format&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
          &lt;span class="c1"&gt;-- Mostra da quale source proviene&lt;/span&gt;
          &lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;menu&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;
            &lt;span class="n"&gt;nvim_lsp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"[LSP]"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;luasnip&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"[Snippet]"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;buffer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"[Buffer]"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"[Path]"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;nvim_lua&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"[Lua]"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="p"&gt;})[&lt;/span&gt;&lt;span class="n"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&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;item&lt;/span&gt;
        &lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Spiegazione&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;nvim-cmp fornisce autocompletamento intelligente con multiple sources&lt;/li&gt;
&lt;li&gt;LuaSnip è il motore per gli snippet&lt;/li&gt;
&lt;li&gt;Configurato per integrarsi perfettamente con rust-analyzer LSP&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Gitsigns (&lt;code&gt;~/.config/nvim/lua/plugins/gitsigns.lua&lt;/code&gt;)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight lua"&gt;&lt;code&gt;&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="s2"&gt;"lewis6991/gitsigns.nvim"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;event&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s2"&gt;"BufReadPre"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"BufNewFile"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="n"&gt;config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="nb"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"gitsigns"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;setup&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="n"&gt;signs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;add&lt;/span&gt;          &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'┃'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="n"&gt;change&lt;/span&gt;       &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'┃'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="n"&gt;delete&lt;/span&gt;       &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'_'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="n"&gt;topdelete&lt;/span&gt;    &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'‾'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="n"&gt;changedelete&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'~'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="n"&gt;untracked&lt;/span&gt;    &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'┆'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;

      &lt;span class="n"&gt;on_attach&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bufnr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="kd"&gt;local&lt;/span&gt; &lt;span class="n"&gt;gs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;package.loaded&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;gitsigns&lt;/span&gt;

        &lt;span class="c1"&gt;-- Keymaps&lt;/span&gt;
        &lt;span class="kd"&gt;local&lt;/span&gt; &lt;span class="k"&gt;function&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;mode&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;opts&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
          &lt;span class="n"&gt;opts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;opts&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
          &lt;span class="n"&gt;opts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;buffer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bufnr&lt;/span&gt;
          &lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;keymap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mode&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;opts&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;end&lt;/span&gt;

        &lt;span class="c1"&gt;-- Navigazione tra hunks&lt;/span&gt;
        &lt;span class="n"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'n'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;']c'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
          &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;wo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;diff&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s1"&gt;']c'&lt;/span&gt; &lt;span class="k"&gt;end&lt;/span&gt;
          &lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;schedule&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="n"&gt;gs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;next_hunk&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
          &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s1"&gt;'&amp;lt;Ignore&amp;gt;'&lt;/span&gt;
        &lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;expr&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="n"&gt;desc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Next Git hunk'&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;

        &lt;span class="n"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'n'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'[c'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
          &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;wo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;diff&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s1"&gt;'[c'&lt;/span&gt; &lt;span class="k"&gt;end&lt;/span&gt;
          &lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;schedule&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="n"&gt;gs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;prev_hunk&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
          &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s1"&gt;'&amp;lt;Ignore&amp;gt;'&lt;/span&gt;
        &lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;expr&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="n"&gt;desc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Previous Git hunk'&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;

        &lt;span class="c1"&gt;-- Actions&lt;/span&gt;
        &lt;span class="n"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'n'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'&amp;lt;leader&amp;gt;hs'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;gs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stage_hunk&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;desc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Stage hunk'&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
        &lt;span class="n"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'n'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'&amp;lt;leader&amp;gt;hr'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;gs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;reset_hunk&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;desc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Reset hunk'&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
        &lt;span class="n"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'v'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'&amp;lt;leader&amp;gt;hs'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="n"&gt;gs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stage_hunk&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'.'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'v'&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt; &lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;desc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Stage hunk'&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
        &lt;span class="n"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'v'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'&amp;lt;leader&amp;gt;hr'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="n"&gt;gs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;reset_hunk&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'.'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'v'&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt; &lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;desc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Reset hunk'&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
        &lt;span class="n"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'n'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'&amp;lt;leader&amp;gt;hS'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;gs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stage_buffer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;desc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Stage buffer'&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
        &lt;span class="n"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'n'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'&amp;lt;leader&amp;gt;hu'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;gs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;undo_stage_hunk&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;desc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Undo stage hunk'&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
        &lt;span class="n"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'n'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'&amp;lt;leader&amp;gt;hR'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;gs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;reset_buffer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;desc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Reset buffer'&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
        &lt;span class="n"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'n'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'&amp;lt;leader&amp;gt;hp'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;gs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;preview_hunk&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;desc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Preview hunk'&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
        &lt;span class="n"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'n'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'&amp;lt;leader&amp;gt;hb'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="n"&gt;gs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;blame_line&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;full&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="k"&gt;end&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;desc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Blame line'&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
        &lt;span class="n"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'n'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'&amp;lt;leader&amp;gt;hd'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;gs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;diffthis&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;desc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Diff this'&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
        &lt;span class="n"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'n'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'&amp;lt;leader&amp;gt;hD'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="n"&gt;gs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;diffthis&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'~'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;desc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Diff this ~'&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;

        &lt;span class="c1"&gt;-- Text object&lt;/span&gt;
        &lt;span class="n"&gt;map&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="s1"&gt;'o'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'x'&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="s1"&gt;'ih'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;':&amp;lt;C-U&amp;gt;Gitsigns select_hunk&amp;lt;CR&amp;gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;desc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Select hunk'&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
      &lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Spiegazione&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Mostra modifiche Git nella sign column (barra a sinistra)&lt;/li&gt;
&lt;li&gt;Navigazione rapida tra modifiche con &lt;code&gt;]c&lt;/code&gt; e &lt;code&gt;[c&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Stage/reset hunks direttamente da Neovim&lt;/li&gt;
&lt;li&gt;Preview delle modifiche inline&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Fugitive (&lt;code&gt;~/.config/nvim/lua/plugins/fugitive.lua&lt;/code&gt;)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight lua"&gt;&lt;code&gt;&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="s2"&gt;"tpope/vim-fugitive"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;cmd&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s2"&gt;"Git"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"G"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"Gdiffsplit"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"Gread"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"Gwrite"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"Ggrep"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"GMove"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"GRename"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"GDelete"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"GBrowse"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="n"&gt;keys&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="s2"&gt;"&amp;lt;leader&amp;gt;gs"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&amp;lt;cmd&amp;gt;Git&amp;lt;cr&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;desc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Git status"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s2"&gt;"&amp;lt;leader&amp;gt;gc"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&amp;lt;cmd&amp;gt;Git commit&amp;lt;cr&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;desc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Git commit"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s2"&gt;"&amp;lt;leader&amp;gt;gp"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&amp;lt;cmd&amp;gt;Git push&amp;lt;cr&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;desc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Git push"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s2"&gt;"&amp;lt;leader&amp;gt;gl"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&amp;lt;cmd&amp;gt;Git pull&amp;lt;cr&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;desc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Git pull"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s2"&gt;"&amp;lt;leader&amp;gt;gb"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&amp;lt;cmd&amp;gt;Git blame&amp;lt;cr&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;desc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Git blame"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s2"&gt;"&amp;lt;leader&amp;gt;gd"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&amp;lt;cmd&amp;gt;Gdiffsplit&amp;lt;cr&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;desc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Git diff split"&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;&lt;strong&gt;Spiegazione&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Interfaccia completa a Git direttamente da Neovim&lt;/li&gt;
&lt;li&gt;Comandi Git nativi (commit, push, pull, blame, diff)&lt;/li&gt;
&lt;li&gt;Si integra perfettamente con Gitsigns&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Which-Key (&lt;code&gt;~/.config/nvim/lua/plugins/which-key.lua&lt;/code&gt;)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight lua"&gt;&lt;code&gt;&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="s2"&gt;"folke/which-key.nvim"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;event&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"VeryLazy"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;init&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;timeout&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;timeoutlen&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;300&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="kd"&gt;local&lt;/span&gt; &lt;span class="n"&gt;wk&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"which-key"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;wk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setup&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="n"&gt;preset&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"modern"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="n"&gt;win&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;border&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"rounded"&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="c1"&gt;-- Registra gruppi di keybindings&lt;/span&gt;
    &lt;span class="n"&gt;wk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s2"&gt;"&amp;lt;leader&amp;gt;f"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;group&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"find"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s2"&gt;"&amp;lt;leader&amp;gt;r"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;group&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"rust"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s2"&gt;"&amp;lt;leader&amp;gt;g"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;group&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"git"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s2"&gt;"&amp;lt;leader&amp;gt;h"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;group&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"hunk"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s2"&gt;"&amp;lt;leader&amp;gt;d"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;group&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"debug"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s2"&gt;"&amp;lt;leader&amp;gt;x"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;group&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"diagnostics"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Spiegazione&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Mostra automaticamente popup con keybindings disponibili&lt;/li&gt;
&lt;li&gt;Aiuta a scoprire e ricordare i comandi&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Trouble (&lt;code&gt;~/.config/nvim/lua/plugins/trouble.lua&lt;/code&gt;)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight lua"&gt;&lt;code&gt;&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="s2"&gt;"folke/trouble.nvim"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;dependencies&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s2"&gt;"nvim-tree/nvim-web-devicons"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="n"&gt;cmd&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s2"&gt;"Trouble"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="n"&gt;keys&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="s2"&gt;"&amp;lt;leader&amp;gt;xx"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&amp;lt;cmd&amp;gt;Trouble diagnostics toggle&amp;lt;cr&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;desc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Diagnostics (Trouble)"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s2"&gt;"&amp;lt;leader&amp;gt;xX"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&amp;lt;cmd&amp;gt;Trouble diagnostics toggle filter.buf=0&amp;lt;cr&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;desc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Buffer Diagnostics (Trouble)"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s2"&gt;"&amp;lt;leader&amp;gt;xs"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&amp;lt;cmd&amp;gt;Trouble symbols toggle focus=false&amp;lt;cr&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;desc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Symbols (Trouble)"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s2"&gt;"&amp;lt;leader&amp;gt;xl"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&amp;lt;cmd&amp;gt;Trouble lsp toggle focus=false win.position=right&amp;lt;cr&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;desc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"LSP Definitions / references / ... (Trouble)"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s2"&gt;"&amp;lt;leader&amp;gt;xL"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&amp;lt;cmd&amp;gt;Trouble loclist toggle&amp;lt;cr&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;desc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Location List (Trouble)"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s2"&gt;"&amp;lt;leader&amp;gt;xQ"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&amp;lt;cmd&amp;gt;Trouble qflist toggle&amp;lt;cr&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;desc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Quickfix List (Trouble)"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="n"&gt;opts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;-- Configurazione opzionale&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Spiegazione&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Mostra lista organizzata di tutti gli errori/warning del progetto&lt;/li&gt;
&lt;li&gt;Visualizzazione migliore della quickfix list di default&lt;/li&gt;
&lt;li&gt;Integrazione con LSP per diagnostics, references, definitions&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Fidget (&lt;code&gt;~/.config/nvim/lua/plugins/fidget.lua&lt;/code&gt;)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight lua"&gt;&lt;code&gt;&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="s2"&gt;"j-hui/fidget.nvim"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;opts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;notification&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;window&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;winblend&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="c1"&gt;-- Trasparenza finestra (0-100)&lt;/span&gt;
        &lt;span class="n"&gt;border&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"none"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="n"&gt;progress&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;display&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;done_icon&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="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;&lt;strong&gt;Spiegazione&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Mostra notifiche LSP in basso a destra (es. "rust-analyzer: indexing...")&lt;/li&gt;
&lt;li&gt;Progress indicator quando rust-analyzer sta analizzando il codice&lt;/li&gt;
&lt;li&gt;Interfaccia pulita e non invasiva&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Treesitter (&lt;code&gt;~/.config/nvim/lua/plugins/treesitter.lua&lt;/code&gt;)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight lua"&gt;&lt;code&gt;&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="s2"&gt;"nvim-treesitter/nvim-treesitter"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;build&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;":TSUpdate"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;event&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s2"&gt;"BufReadPost"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"BufNewFile"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="n"&gt;dependencies&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="s2"&gt;"nvim-treesitter/nvim-treesitter-textobjects"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="c1"&gt;-- Text objects avanzati&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="n"&gt;config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="nb"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"nvim-treesitter.configs"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;setup&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="c1"&gt;-- Linguaggi da installare automaticamente&lt;/span&gt;
      &lt;span class="n"&gt;ensure_installed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="s2"&gt;"rust"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s2"&gt;"toml"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s2"&gt;"lua"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s2"&gt;"vim"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s2"&gt;"vimdoc"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s2"&gt;"markdown"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s2"&gt;"markdown_inline"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s2"&gt;"json"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s2"&gt;"yaml"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;

      &lt;span class="c1"&gt;-- Installa parser in modo sincrono&lt;/span&gt;
      &lt;span class="n"&gt;sync_install&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

      &lt;span class="c1"&gt;-- Installazione automatica parser mancanti&lt;/span&gt;
      &lt;span class="n"&gt;auto_install&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="c1"&gt;-- Syntax highlighting&lt;/span&gt;
      &lt;span class="n"&gt;highlight&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;enable&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="n"&gt;additional_vim_regex_highlighting&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;

      &lt;span class="c1"&gt;-- Indentazione basata su treesitter&lt;/span&gt;
      &lt;span class="n"&gt;indent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;enable&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="c1"&gt;-- Selezione incrementale&lt;/span&gt;
      &lt;span class="n"&gt;incremental_selection&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;enable&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="n"&gt;keymaps&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="n"&gt;init_selection&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"&amp;lt;CR&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="n"&gt;node_incremental&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"&amp;lt;CR&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="n"&gt;node_decremental&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"&amp;lt;BS&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="n"&gt;scope_incremental&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"&amp;lt;TAB&amp;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="c1"&gt;-- Text objects&lt;/span&gt;
      &lt;span class="n"&gt;textobjects&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nb"&gt;select&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="n"&gt;enable&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="n"&gt;lookahead&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="n"&gt;keymaps&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="s2"&gt;"af"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"@function.outer"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"if"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"@function.inner"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"ac"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"@class.outer"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"ic"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"@class.inner"&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;span class="k"&gt;end&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Telescope (&lt;code&gt;~/.config/nvim/lua/plugins/telescope.lua&lt;/code&gt;)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight lua"&gt;&lt;code&gt;&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="s2"&gt;"nvim-telescope/telescope.nvim"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;branch&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"0.1.x"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;dependencies&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="s2"&gt;"nvim-lua/plenary.nvim"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="s2"&gt;"nvim-telescope/telescope-fzf-native.nvim"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="n"&gt;build&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"make"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="c1"&gt;-- Compilazione per performance migliori&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="n"&gt;config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="kd"&gt;local&lt;/span&gt; &lt;span class="n"&gt;telescope&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"telescope"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;local&lt;/span&gt; &lt;span class="n"&gt;actions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"telescope.actions"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;telescope&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setup&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="n"&gt;defaults&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;path_display&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s2"&gt;"truncate"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="n"&gt;mappings&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="n"&gt;i&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="s2"&gt;"&amp;lt;C-k&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;actions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;move_selection_previous&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&amp;lt;C-j&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;actions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;move_selection_next&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&amp;lt;C-q&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;actions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;send_selected_to_qflist&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;actions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;open_qflist&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="n"&gt;pickers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;find_files&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="n"&gt;hidden&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="c1"&gt;-- Mostra file nascosti&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="c1"&gt;-- Carica estensione fzf&lt;/span&gt;
    &lt;span class="n"&gt;telescope&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;load_extension&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"fzf"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;-- Keymaps&lt;/span&gt;
    &lt;span class="kd"&gt;local&lt;/span&gt; &lt;span class="n"&gt;builtin&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"telescope.builtin"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;keymap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'n'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'&amp;lt;leader&amp;gt;ff'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;builtin&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;find_files&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;desc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Find Files'&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;keymap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'n'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'&amp;lt;leader&amp;gt;fg'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;builtin&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;live_grep&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;desc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Live Grep'&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;keymap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'n'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'&amp;lt;leader&amp;gt;fb'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;builtin&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;buffers&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;desc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Buffers'&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;keymap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'n'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'&amp;lt;leader&amp;gt;fh'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;builtin&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;help_tags&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;desc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Help Tags'&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;keymap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'n'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'&amp;lt;leader&amp;gt;fr'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;builtin&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;lsp_references&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;desc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'LSP References'&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;keymap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'n'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'&amp;lt;leader&amp;gt;fs'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;builtin&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;lsp_document_symbols&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;desc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Document Symbols'&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Oil.nvim (&lt;code&gt;~/.config/nvim/lua/plugins/oil.lua&lt;/code&gt;)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight lua"&gt;&lt;code&gt;&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="s2"&gt;"stevearc/oil.nvim"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;dependencies&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s2"&gt;"nvim-tree/nvim-web-devicons"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="n"&gt;config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="nb"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"oil"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;setup&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="c1"&gt;-- Colonne da mostrare&lt;/span&gt;
      &lt;span class="n"&gt;columns&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="s2"&gt;"icon"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s2"&gt;"permissions"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s2"&gt;"size"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s2"&gt;"mtime"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;

      &lt;span class="c1"&gt;-- Keymaps dentro oil&lt;/span&gt;
      &lt;span class="n"&gt;keymaps&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="s2"&gt;"g?"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"actions.show_help"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&amp;lt;CR&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"actions.select"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&amp;lt;C-v&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"actions.select_vsplit"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&amp;lt;C-s&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"actions.select_split"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&amp;lt;C-t&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"actions.select_tab"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&amp;lt;C-p&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"actions.preview"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&amp;lt;C-c&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"actions.close"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&amp;lt;C-r&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"actions.refresh"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"-"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"actions.parent"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"_"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"actions.open_cwd"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"`"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"actions.cd"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"~"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"actions.tcd"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"gs"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"actions.change_sort"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"gx"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"actions.open_external"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"g."&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"actions.toggle_hidden"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;

      &lt;span class="c1"&gt;-- Mostra file nascosti di default&lt;/span&gt;
      &lt;span class="n"&gt;view_options&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;show_hidden&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="c1"&gt;-- Apri oil con -&lt;/span&gt;
    &lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;keymap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"n"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"-"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&amp;lt;CMD&amp;gt;Oil&amp;lt;CR&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;desc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Open parent directory"&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Rustaceanvim (&lt;code&gt;~/.config/nvim/lua/plugins/rustacean.lua&lt;/code&gt;)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight lua"&gt;&lt;code&gt;&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="s2"&gt;"mrcjkb/rustaceanvim"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;version&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"^5"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;ft&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s2"&gt;"rust"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;  &lt;span class="c1"&gt;-- Carica solo per file Rust&lt;/span&gt;
  &lt;span class="n"&gt;config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rustaceanvim&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;-- LSP settings&lt;/span&gt;
      &lt;span class="n"&gt;server&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;on_attach&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;bufnr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
          &lt;span class="c1"&gt;-- Keymaps per LSP&lt;/span&gt;
          &lt;span class="kd"&gt;local&lt;/span&gt; &lt;span class="n"&gt;opts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;buffer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bufnr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;noremap&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="n"&gt;silent&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="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;keymap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'n'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'gd'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;lsp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;definition&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;opts&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
          &lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;keymap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'n'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'gD'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;lsp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;declaration&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;opts&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
          &lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;keymap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'n'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'gi'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;lsp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;implementation&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;opts&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
          &lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;keymap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'n'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'gr'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;lsp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;references&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;opts&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
          &lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;keymap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'n'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'K'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;lsp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;hover&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;opts&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
          &lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;keymap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'n'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'&amp;lt;leader&amp;gt;rn'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;lsp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rename&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;opts&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
          &lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;keymap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'n'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'&amp;lt;leader&amp;gt;ca'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;lsp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;code_action&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;opts&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
          &lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;keymap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'n'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'&amp;lt;leader&amp;gt;f'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;lsp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;format&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;opts&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

          &lt;span class="c1"&gt;-- Rustacean specific&lt;/span&gt;
          &lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;keymap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'n'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'&amp;lt;leader&amp;gt;rd'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'&amp;lt;cmd&amp;gt;RustLsp debuggables&amp;lt;cr&amp;gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;opts&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
          &lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;keymap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'n'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'&amp;lt;leader&amp;gt;rr'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'&amp;lt;cmd&amp;gt;RustLsp runnables&amp;lt;cr&amp;gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;opts&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
          &lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;keymap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'n'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'&amp;lt;leader&amp;gt;rt'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'&amp;lt;cmd&amp;gt;RustLsp testables&amp;lt;cr&amp;gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;opts&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
          &lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;keymap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'n'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'&amp;lt;leader&amp;gt;re'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'&amp;lt;cmd&amp;gt;RustLsp expandMacro&amp;lt;cr&amp;gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;opts&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

        &lt;span class="n"&gt;default_settings&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="s1"&gt;'rust-analyzer'&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="n"&gt;cargo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
              &lt;span class="n"&gt;allFeatures&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="n"&gt;loadOutDirsFromCheck&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="n"&gt;buildScripts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;enable&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="c1"&gt;-- Usa 'check' invece di 'checkOnSave'&lt;/span&gt;
            &lt;span class="n"&gt;check&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
              &lt;span class="n"&gt;command&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"clippy"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="c1"&gt;-- Usa clippy invece di check&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="n"&gt;procMacro&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
              &lt;span class="n"&gt;enable&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="n"&gt;diagnostics&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
              &lt;span class="n"&gt;enable&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="n"&gt;experimental&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;enable&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="p"&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;-- DAP (Debug Adapter Protocol)&lt;/span&gt;
      &lt;span class="n"&gt;dap&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;adapter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="nb"&gt;type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"server"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="n"&gt;port&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"${port}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="n"&gt;executable&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;command&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stdpath&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"data"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;..&lt;/span&gt; &lt;span class="s2"&gt;"/mason/bin/codelldb"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;args&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s2"&gt;"--port"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"${port}"&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;span class="k"&gt;end&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;dependencies&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;-- Plugin per debugging&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="s2"&gt;"mfussenegger/nvim-dap"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="n"&gt;config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="kd"&gt;local&lt;/span&gt; &lt;span class="n"&gt;dap&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"dap"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="c1"&gt;-- Keymaps per debugging&lt;/span&gt;
        &lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;keymap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'n'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'&amp;lt;F5&amp;gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;continue&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;desc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Debug: Start/Continue'&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
        &lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;keymap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'n'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'&amp;lt;F10&amp;gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;step_over&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;desc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Debug: Step Over'&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
        &lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;keymap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'n'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'&amp;lt;F11&amp;gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;step_into&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;desc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Debug: Step Into'&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
        &lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;keymap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'n'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'&amp;lt;F12&amp;gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;step_out&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;desc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Debug: Step Out'&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
        &lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;keymap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'n'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'&amp;lt;leader&amp;gt;b'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;toggle_breakpoint&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;desc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Debug: Toggle Breakpoint'&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
      &lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;

    &lt;span class="c1"&gt;-- UI per il debugger&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="s2"&gt;"rcarriga/nvim-dap-ui"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="n"&gt;dependencies&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s2"&gt;"nvim-neotest/nvim-nio"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="n"&gt;config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="kd"&gt;local&lt;/span&gt; &lt;span class="n"&gt;dap&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dapui&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"dap"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nb"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"dapui"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="n"&gt;dapui&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setup&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

        &lt;span class="c1"&gt;-- Apri/chiudi automaticamente UI&lt;/span&gt;
        &lt;span class="n"&gt;dap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;listeners&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;after&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;event_initialized&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"dapui_config"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
          &lt;span class="n"&gt;dapui&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;open&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="k"&gt;end&lt;/span&gt;
        &lt;span class="n"&gt;dap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;listeners&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;before&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;event_terminated&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"dapui_config"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
          &lt;span class="n"&gt;dapui&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="k"&gt;end&lt;/span&gt;
        &lt;span class="n"&gt;dap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;listeners&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;before&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;event_exited&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"dapui_config"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
          &lt;span class="n"&gt;dapui&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="k"&gt;end&lt;/span&gt;

        &lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;keymap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'n'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'&amp;lt;leader&amp;gt;du'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dapui&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;toggle&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;desc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Debug: Toggle UI'&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
      &lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;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;h3&gt;
  
  
  6.9 Lualine (&lt;code&gt;~/.config/nvim/lua/plugins/lualine.lua&lt;/code&gt;)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight lua"&gt;&lt;code&gt;&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="s2"&gt;"nvim-lualine/lualine.nvim"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;dependencies&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s2"&gt;"nvim-tree/nvim-web-devicons"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="n"&gt;config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="nb"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"lualine"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;setup&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="n"&gt;options&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;theme&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"gruvbox-material"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;component_separators&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;left&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'|'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;right&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'|'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="n"&gt;section_separators&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;left&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;''&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;right&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;''&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="n"&gt;globalstatus&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="c1"&gt;-- Una statusline per tutte le finestre&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="n"&gt;sections&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;lualine_a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s1"&gt;'mode'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="n"&gt;lualine_b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s1"&gt;'branch'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'diff'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="n"&gt;lualine_c&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="s1"&gt;'filename'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="c1"&gt;-- 0 = solo nome, 1 = relativo, 2 = assoluto&lt;/span&gt;
          &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="n"&gt;lualine_x&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="s1"&gt;'diagnostics'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;sources&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s1"&gt;'nvim_diagnostic'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="n"&gt;symbols&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nb"&gt;error&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;' '&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;warn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;' '&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;info&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;' '&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;hint&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;' '&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
          &lt;span class="p"&gt;},&lt;/span&gt;
          &lt;span class="s1"&gt;'encoding'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="s1"&gt;'fileformat'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="s1"&gt;'filetype'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="n"&gt;lualine_y&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s1"&gt;'progress'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="n"&gt;lualine_z&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s1"&gt;'location'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="n"&gt;inactive_sections&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;lualine_a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{},&lt;/span&gt;
        &lt;span class="n"&gt;lualine_b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{},&lt;/span&gt;
        &lt;span class="n"&gt;lualine_c&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s1"&gt;'filename'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="n"&gt;lualine_x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s1"&gt;'location'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="n"&gt;lualine_y&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{},&lt;/span&gt;
        &lt;span class="n"&gt;lualine_z&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="n"&gt;extensions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s1"&gt;'fugitive'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'oil'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'trouble'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Gruvbox Material (&lt;code&gt;~/.config/nvim/lua/plugins/colorscheme.lua&lt;/code&gt;)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight lua"&gt;&lt;code&gt;&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="s2"&gt;"sainnhe/gruvbox-material"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;lazy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;     &lt;span class="c1"&gt;-- Carica immediatamente&lt;/span&gt;
  &lt;span class="n"&gt;priority&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="c1"&gt;-- Carica prima di altri plugin&lt;/span&gt;
  &lt;span class="n"&gt;config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="c1"&gt;-- Configura il colorscheme&lt;/span&gt;
    &lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;gruvbox_material_background&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'medium'&lt;/span&gt;  &lt;span class="c1"&gt;-- 'soft', 'medium', 'hard'&lt;/span&gt;
    &lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;gruvbox_material_better_performance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;gruvbox_material_enable_italic&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;

    &lt;span class="c1"&gt;-- Applica il colorscheme&lt;/span&gt;
    &lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cmd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;colorscheme&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'gruvbox-material'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Test e Verifica
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Prima apertura di Neovim
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nvim
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Al primo avvio, Lazy.nvim installerà automaticamente tutti i plugin. Vedrai una finestra con il progresso dell'installazione. Mason installerà anche automaticamente codelldb in background.&lt;/p&gt;

&lt;h3&gt;
  
  
  Verifica installazione plugin
&lt;/h3&gt;

&lt;p&gt;Dentro Neovim, digita:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight viml"&gt;&lt;code&gt;&lt;span class="p"&gt;:&lt;/span&gt;Lazy
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Dovresti vedere tutti i plugin installati con segno di spunta verde.&lt;/p&gt;

&lt;p&gt;Per verificare che codelldb sia stato installato:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight viml"&gt;&lt;code&gt;&lt;span class="p"&gt;:&lt;/span&gt;Mason
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Dovresti vedere &lt;code&gt;codelldb&lt;/code&gt; con il segno ✓ (installato).&lt;/p&gt;

&lt;h3&gt;
  
  
  Verifica Treesitter
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight viml"&gt;&lt;code&gt;&lt;span class="p"&gt;:&lt;/span&gt;checkhealth nvim&lt;span class="p"&gt;-&lt;/span&gt;treesitter
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Test con progetto Rust
&lt;/h3&gt;

&lt;p&gt;Crea un progetto di test:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;cargo new test_project
&lt;span class="nb"&gt;cd &lt;/span&gt;test_project
nvim src/main.rs
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Dovresti vedere:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✅ Syntax highlighting colorato&lt;/li&gt;
&lt;li&gt;✅ Autocompletamento (premi &lt;code&gt;Ctrl+Space&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;✅ Diagnostica inline (errori/warning sottolineati)&lt;/li&gt;
&lt;li&gt;✅ Hover documentation (premi &lt;code&gt;K&lt;/code&gt; su una funzione)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Test debugging
&lt;/h3&gt;

&lt;p&gt;Nel file &lt;code&gt;src/main.rs&lt;/code&gt;, aggiungi:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nd"&gt;println!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Sum: {}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;  &lt;span class="c1"&gt;// Metti breakpoint qui&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Premi &lt;code&gt;&amp;lt;leader&amp;gt;b&lt;/code&gt; sulla riga del println per aggiungere breakpoint&lt;/li&gt;
&lt;li&gt;Premi &lt;code&gt;&amp;lt;leader&amp;gt;rd&lt;/code&gt; per vedere opzioni di debug&lt;/li&gt;
&lt;li&gt;Seleziona "Debug" e premi Enter&lt;/li&gt;
&lt;li&gt;Usa &lt;code&gt;F10&lt;/code&gt; per step over, &lt;code&gt;F11&lt;/code&gt; per step into&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Comandi Utili
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Plugin Management (Lazy.nvim)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;:Lazy&lt;/code&gt; - Apri interfaccia Lazy&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;:Lazy update&lt;/code&gt; - Aggiorna tutti i plugin&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;:Lazy sync&lt;/code&gt; - Installa/aggiorna/rimuovi plugin&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Mason (Package Manager)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;:Mason&lt;/code&gt; - Apri interfaccia Mason&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;:MasonInstall &amp;lt;package&amp;gt;&lt;/code&gt; - Installa un package&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;:MasonUninstall &amp;lt;package&amp;gt;&lt;/code&gt; - Rimuovi un package&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;&amp;lt;leader&amp;gt;m&lt;/code&gt; - Apri Mason&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Autocompletamento (nvim-cmp)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;Ctrl+Space&lt;/code&gt; - Trigger completamento manualmente&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Ctrl+j/k&lt;/code&gt; - Naviga suggerimenti&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Tab/Shift+Tab&lt;/code&gt; - Naviga snippet&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Enter&lt;/code&gt; - Conferma selezione&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Ctrl+e&lt;/code&gt; - Chiudi menu completamento&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Telescope
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;&amp;lt;leader&amp;gt;ff&lt;/code&gt; - Find files&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;&amp;lt;leader&amp;gt;fg&lt;/code&gt; - Live grep (ricerca in tutti i file)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;&amp;lt;leader&amp;gt;fb&lt;/code&gt; - Lista buffer aperti&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;&amp;lt;leader&amp;gt;fr&lt;/code&gt; - Trova riferimenti LSP&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;&amp;lt;leader&amp;gt;fs&lt;/code&gt; - Simboli del documento&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Oil.nvim
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;-&lt;/code&gt; - Apri directory corrente&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;&amp;lt;CR&amp;gt;&lt;/code&gt; - Entra in directory/apri file&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;&amp;lt;C-s&amp;gt;&lt;/code&gt; - Apri in split orizzontale&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;&amp;lt;C-v&amp;gt;&lt;/code&gt; - Apri in split verticale&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;g.&lt;/code&gt; - Toggle file nascosti&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  LSP
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;gd&lt;/code&gt; - Go to definition&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;gr&lt;/code&gt; - Go to references&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;K&lt;/code&gt; - Hover documentation&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;&amp;lt;leader&amp;gt;rn&lt;/code&gt; - Rename symbol&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;&amp;lt;leader&amp;gt;ca&lt;/code&gt; - Code actions&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;&amp;lt;leader&amp;gt;f&lt;/code&gt; - Format document&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Diagnostics
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;&amp;lt;leader&amp;gt;e&lt;/code&gt; - Show diagnostic popup (errore/warning riga corrente)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;]d&lt;/code&gt; - Next diagnostic&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;[d&lt;/code&gt; - Previous diagnostic&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Rust Specific
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;&amp;lt;leader&amp;gt;rr&lt;/code&gt; - Rust runnables (esegui main, esempi, etc.)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;&amp;lt;leader&amp;gt;rt&lt;/code&gt; - Rust testables (esegui test)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;&amp;lt;leader&amp;gt;rd&lt;/code&gt; - Rust debuggables (debug)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;&amp;lt;leader&amp;gt;re&lt;/code&gt; - Expand macro&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Debugging
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;&amp;lt;F5&amp;gt;&lt;/code&gt; - Start/Continue debug&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;&amp;lt;F10&amp;gt;&lt;/code&gt; - Step over&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;&amp;lt;F11&amp;gt;&lt;/code&gt; - Step into&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;&amp;lt;F12&amp;gt;&lt;/code&gt; - Step out&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;&amp;lt;leader&amp;gt;b&lt;/code&gt; - Toggle breakpoint&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;&amp;lt;leader&amp;gt;du&lt;/code&gt; - Toggle debug UI&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Git (Gitsigns)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;]c&lt;/code&gt; / &lt;code&gt;[c&lt;/code&gt; - Next/Previous hunk&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;&amp;lt;leader&amp;gt;hs&lt;/code&gt; - Stage hunk&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;&amp;lt;leader&amp;gt;hr&lt;/code&gt; - Reset hunk&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;&amp;lt;leader&amp;gt;hS&lt;/code&gt; - Stage buffer&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;&amp;lt;leader&amp;gt;hp&lt;/code&gt; - Preview hunk&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;&amp;lt;leader&amp;gt;hb&lt;/code&gt; - Blame line&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;&amp;lt;leader&amp;gt;hd&lt;/code&gt; - Diff this&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ih&lt;/code&gt; - Select hunk (text object)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Git (Fugitive)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;&amp;lt;leader&amp;gt;gs&lt;/code&gt; - Git status&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;&amp;lt;leader&amp;gt;gc&lt;/code&gt; - Git commit&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;&amp;lt;leader&amp;gt;gp&lt;/code&gt; - Git push&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;&amp;lt;leader&amp;gt;gl&lt;/code&gt; - Git pull&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;&amp;lt;leader&amp;gt;gb&lt;/code&gt; - Git blame&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;&amp;lt;leader&amp;gt;gd&lt;/code&gt; - Git diff split&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Which-Key
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;&amp;lt;leader&amp;gt;&lt;/code&gt; - Mostra tutti i keybindings del leader&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Trouble (Diagnostics)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;&amp;lt;leader&amp;gt;xx&lt;/code&gt; - Toggle diagnostics&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;&amp;lt;leader&amp;gt;xX&lt;/code&gt; - Toggle buffer diagnostics&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;&amp;lt;leader&amp;gt;xs&lt;/code&gt; - Toggle symbols&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;&amp;lt;leader&amp;gt;xl&lt;/code&gt; - Toggle LSP info&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;&amp;lt;leader&amp;gt;xQ&lt;/code&gt; - Toggle quickfix&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Treesitter
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;:TSUpdate&lt;/code&gt; - Aggiorna parser&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;:TSInstall &amp;lt;lang&amp;gt;&lt;/code&gt; - Installa parser per linguaggio&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;&amp;lt;CR&amp;gt;&lt;/code&gt; in visual mode - Selezione incrementale&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Troubleshooting
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Problema: Treesitter non compila parser
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Installa dipendenze C&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; gcc g++

&lt;span class="c"&gt;# In Neovim&lt;/span&gt;
:TSInstall rust
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Warning: tree-sitter executable not found
&lt;/h3&gt;

&lt;p&gt;Questo è un warning comune e &lt;strong&gt;completamente normale&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;⚠️ WARNING tree-sitter executable not found (parser generator, only needed for :TSInstallFromGrammar)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Per eliminare il warning (opzionale):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Installa tree-sitter CLI&lt;/span&gt;
cargo &lt;span class="nb"&gt;install &lt;/span&gt;tree-sitter-cli
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Dopo l'installazione, riavvia Neovim e il warning sparirà. Ma ripeto: è puramente estetico, la funzionalità è già completa!&lt;/p&gt;

&lt;h3&gt;
  
  
  Warning: mini.icons is not installed
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;⚠️ WARNING mini.icons is not installed
✅ OK nvim-web-devicons is installed
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Cosa significa:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;which-key può usare &lt;code&gt;mini.icons&lt;/code&gt; OPPURE &lt;code&gt;nvim-web-devicons&lt;/code&gt; per le icone&lt;/li&gt;
&lt;li&gt;La nostra config usa &lt;code&gt;nvim-web-devicons&lt;/code&gt; (già installato con Oil e Trouble)&lt;/li&gt;
&lt;li&gt;Il warning è solo informativo, le icone funzionano perfettamente&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Problema: Telescope non trova file
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Verifica ripgrep e fd&lt;/span&gt;
which rg
which fd

&lt;span class="c"&gt;# Ubuntu: Se mancano, reinstalla&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;ripgrep fd-find

&lt;span class="c"&gt;# macOS: Se mancano, reinstalla&lt;/span&gt;
brew &lt;span class="nb"&gt;install &lt;/span&gt;ripgrep fd
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Prossimi Passi e Personalizzazioni
&lt;/h2&gt;

&lt;p&gt;Ora hai un IDE Rust &lt;strong&gt;completo e professionale&lt;/strong&gt;! 🎉&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cosa hai ottenuto:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✅ Autocompletamento intelligente con nvim-cmp&lt;/li&gt;
&lt;li&gt;✅ Integrazione Git completa (Gitsigns + Fugitive)&lt;/li&gt;
&lt;li&gt;✅ Diagnostics organizzate (Trouble)&lt;/li&gt;
&lt;li&gt;✅ Notifiche LSP eleganti (Fidget)&lt;/li&gt;
&lt;li&gt;✅ Guida ai keybindings (Which-Key)&lt;/li&gt;
&lt;li&gt;✅ Debugging visuale completo&lt;/li&gt;
&lt;li&gt;✅ Syntax highlighting avanzato&lt;/li&gt;
&lt;li&gt;✅ File explorer moderno (Oil)&lt;/li&gt;
&lt;li&gt;✅ Ricerca potente (Telescope)&lt;/li&gt;
&lt;li&gt;✅ Statusline informativa (Lualine)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Considera di aggiungere (opzionale):&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;toggleterm.nvim&lt;/strong&gt; - Terminale integrato e toggleable&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;nvim-autopairs&lt;/strong&gt; - Chiusura automatica di parentesi/virgolette&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Comment.nvim&lt;/strong&gt; - Commenta codice facilmente con &lt;code&gt;gc&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;indent-blankline.nvim&lt;/strong&gt; - Mostra guide di indentazione&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;nvim-colorizer.lua&lt;/strong&gt; - Evidenzia codici colore nel codice&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;rust-tools.nvim&lt;/strong&gt; - Tools extra per Rust (hover actions, ecc.)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Risorse utili:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Documentazione Neovim: &lt;code&gt;:help&lt;/code&gt; o &lt;a href="https://neovim.io/doc/" rel="noopener noreferrer"&gt;https://neovim.io/doc/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;rust-analyzer docs: &lt;a href="https://rust-analyzer.github.io/" rel="noopener noreferrer"&gt;https://rust-analyzer.github.io/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Awesome Neovim: &lt;a href="https://github.com/rockerBOO/awesome-neovim" rel="noopener noreferrer"&gt;https://github.com/rockerBOO/awesome-neovim&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Buon coding! 🦀&lt;/p&gt;

</description>
      <category>rust</category>
      <category>neovim</category>
      <category>development</category>
    </item>
    <item>
      <title>Aumentare la produttività con Tmux e Vim</title>
      <dc:creator>Marco Bollero</dc:creator>
      <pubDate>Tue, 28 Jan 2025 09:00:00 +0000</pubDate>
      <link>https://dev.to/marco_bollero_ba3c38ddd27/aumentare-la-produttivita-con-tmux-e-vim-1dc</link>
      <guid>https://dev.to/marco_bollero_ba3c38ddd27/aumentare-la-produttivita-con-tmux-e-vim-1dc</guid>
      <description>&lt;h2&gt;
  
  
  L'idea
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;Tanto tempo fa, in una galassia lontana lontana... &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Ops, scusate, è che quando scrivo "&lt;em&gt;tanto tempo fa&lt;/em&gt;", poi le dita vanno avanti da sole 😃&lt;/p&gt;

&lt;p&gt;Dicevamo... tempo fa, mi sono imbattuto in un video del &lt;a href="https://www.youtube.com/@ThePrimeTimeagen" rel="noopener noreferrer"&gt;noto youtuber ThePrimeagen&lt;/a&gt; (vi consiglio di seguirlo, è interessante e spesso divertente ma non soltanto per la sua voce che sembra un cartone animato) in cui parlava del suo &lt;em&gt;workflow&lt;/em&gt;, cioè del suo flusso di lavoro: con solo due tasti apriva una nuova sessione &lt;code&gt;tmux&lt;/code&gt; (o la ripristinava se già presente) e "&lt;em&gt;auto-magicamente&lt;/em&gt;" si trovava &lt;code&gt;vim&lt;/code&gt; aperto pronto per lavorare! Se non è questa &lt;strong&gt;produttività&lt;/strong&gt;?!?!?!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Una figata pazzesca!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Allora mi sono detto: lo posso fare anch'io, ne ho tutte le capacità ed anch'io ho la voce che sembro Paperino 😃&lt;/p&gt;

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

&lt;h2&gt;
  
  
  Mettiamoci a lavoro!
&lt;/h2&gt;

&lt;p&gt;In realtà la cosa è stata abbastanza semplice, per prima cosa mi serviva un file di configurazione con tutti i &lt;code&gt;path&lt;/code&gt; dove solitamente memorizzo i miei progetti, ho deciso di chiamare il file: &lt;code&gt;mp_folders&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Sicuramente vi starete domandando "&lt;em&gt;ma perché inizia per mp?!?!?!&lt;/em&gt;"&lt;/p&gt;

&lt;p&gt;Eh, bella domanda, lo capirete a breve 😊&lt;/p&gt;

&lt;p&gt;Perfetto, una volta fatta la lista, mi serve un modo per chiedere all'utente quale progetto vuole aprire, e qui ThePrimeagen suggerisce (giustamente) di usare il &lt;a href="https://github.com/junegunn/fzf" rel="noopener noreferrer"&gt;fzf&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Il fuzzy-finder è un tools a riga di comando per filtrare e selezionare qualsiasi tipo di lista passata in ingresso. Non c'è neanche bisogno di scrivere la stringa esatta! Viene chiamata "ricerca fuzzy", permette cioè di trovare rapidamente elementi all'interno di una lista, anche in presenza di errori di battitura o parole incomplete! &lt;/p&gt;

&lt;p&gt;Ad esempio, avete una lista come la seguente?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mela
banana
pesca
pere
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;per selezionare "pesca" non occorre scrivere &lt;code&gt;pes&lt;/code&gt; &lt;code&gt;pesc&lt;/code&gt; o addirittura &lt;code&gt;pesca&lt;/code&gt;, basta anche solo premere &lt;code&gt;p&lt;/code&gt; e &lt;code&gt;s&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Ok, ora mettiamo mani al codice... usiamo &lt;code&gt;bash&lt;/code&gt; per scrivere un semplice script, come lo chiamiamo?!?!?&lt;/p&gt;

&lt;p&gt;Mumble, mumble... &lt;code&gt;my-project&lt;/code&gt;! No... troppo longo... ok trovato &lt;code&gt;mp&lt;/code&gt;!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#! /bin/bash&lt;/span&gt;

&lt;span class="nv"&gt;LIST&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; &lt;span class="nv"&gt;$HOME&lt;/span&gt;/.config/mp_folders | &lt;span class="nb"&gt;tr&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="s2"&gt;" "&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
&lt;span class="nv"&gt;FOLDER&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;find &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;LIST&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; &lt;span class="nt"&gt;-mindepth&lt;/span&gt; 1 &lt;span class="nt"&gt;-maxdepth&lt;/span&gt; 1 &lt;span class="nt"&gt;-type&lt;/span&gt; d | fzf&lt;span class="si"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;LIST&lt;/code&gt; praticamente sarà valorizzato con l'elenco di tutte le cartelle inserite nel file &lt;code&gt;mp_folders&lt;/code&gt; separate da un semplice spazio.&lt;/p&gt;

&lt;p&gt;Passiamo questa &lt;code&gt;LIST&lt;/code&gt; al comando &lt;code&gt;find&lt;/code&gt; per farci trovare tutte le sotto-cartelle (senza però scendere troppo nell'albero) e passiamo quindi il tutto al nostro amato &lt;code&gt;fzf&lt;/code&gt;.&lt;/p&gt;

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

&lt;p&gt;Bellissimo! Già mi piace! &lt;/p&gt;

&lt;p&gt;Una volta che l'utente preme &lt;code&gt;Invio&lt;/code&gt; all'interno di &lt;code&gt;FOLDER&lt;/code&gt; andrà a finire la cartella selezionata. &lt;/p&gt;

&lt;p&gt;Con questa informazione, ci andiamo a costruire il nome della nostra sessione &lt;code&gt;tmux&lt;/code&gt;, per sicurezza meglio sostituire i punto con l'underscore, casomai qualcuno s'innervosisse&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;NAME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;basename&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;FOLDER&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; | &lt;span class="nb"&gt;tr&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt; _&lt;span class="si"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;tmux&lt;/code&gt; ci consente di creare ma anche modificare sessioni, ad esempio se volessi aggiungere una nuova finestra ad una sessione, mi basta lanciare:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;tmux new-window -n shell -t session1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;così facendo abbiamo aggiunto una nuova finestra alla sessione "session1" dandogli il titolo "shell", ditemi voi se questa non è una figata!&lt;/p&gt;

&lt;p&gt;Ok, mettiamo un po' comandi nello script&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Sessione &amp;lt;&lt;/span&gt;&lt;span class="nv"&gt;$NAME&lt;/span&gt;&lt;span class="s2"&gt;&amp;gt;"&lt;/span&gt;

&lt;span class="k"&gt;if &lt;/span&gt;tmux has-session &lt;span class="nt"&gt;-t&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;NAME&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; 2&amp;gt;/dev/null
&lt;span class="k"&gt;then
  &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"La sessione esiste"&lt;/span&gt;
&lt;span class="k"&gt;else
  &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"La sessione non esiste"&lt;/span&gt;

  tmux new-session &lt;span class="nt"&gt;-ds&lt;/span&gt; &lt;span class="nv"&gt;$NAME&lt;/span&gt; &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="nv"&gt;$FOLDER&lt;/span&gt;
  tmux send-keys &lt;span class="nt"&gt;-t&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;NAME&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;:1 &lt;span class="s2"&gt;"nvim"&lt;/span&gt; Enter
  tmux new-window &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="nv"&gt;$FOLDER&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; shell &lt;span class="nt"&gt;-t&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;NAME&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;:2
  tmux &lt;span class="k"&gt;select&lt;/span&gt;&lt;span class="nt"&gt;-window&lt;/span&gt; &lt;span class="nt"&gt;-t&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;NAME&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;:1
&lt;span class="k"&gt;fi

if&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="nt"&gt;-z&lt;/span&gt; &lt;span class="nv"&gt;$TMUX&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt;
&lt;span class="k"&gt;then&lt;/span&gt;
  &lt;span class="c"&gt;# Non sono già in tmux&lt;/span&gt;
  tmux attach-session &lt;span class="nt"&gt;-t&lt;/span&gt; &lt;span class="nv"&gt;$NAME&lt;/span&gt;
&lt;span class="k"&gt;else&lt;/span&gt;
  &lt;span class="c"&gt;# Sono già in tmux&lt;/span&gt;
  tmux switch-client &lt;span class="nt"&gt;-t&lt;/span&gt; &lt;span class="nv"&gt;$NAME&lt;/span&gt;
&lt;span class="k"&gt;fi&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Lo "spiegone"
&lt;/h2&gt;

&lt;p&gt;Un po' di spiegazioni... &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Per prima cosa controlliamo se la sessione che abbiamo esiste già&lt;/li&gt;
&lt;li&gt;Se c'è, allora non dobbiamo fare nulla e scriviamo solo un commento che potrebbe esserci utile in futuro

&lt;ul&gt;
&lt;li&gt;Se invece non c'è, allora creiamo la sessione col nome che abbiamo costruito e specifichiamo anche la cartella corrente&lt;/li&gt;
&lt;li&gt;Tramite &lt;code&gt;send-keys&lt;/code&gt; diciamo di scrivere &lt;code&gt;nvim&lt;/code&gt; e premere &lt;code&gt;Invio&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Dentro questa sessione, andiamo a creare una nuova finestra che chiamiamo "shell"&lt;/li&gt;
&lt;li&gt;E con &lt;code&gt;select-window&lt;/code&gt; andiamo a selezionare la prima finestra (il nostro editor)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Come ultimo step, andiamo a controllare la variabile di ambiente `TMUX'

&lt;ul&gt;
&lt;li&gt;Se non è impostata non ci troviamo già all'interno di &lt;code&gt;tmux&lt;/code&gt; e quindi usiamo &lt;code&gt;attach-session&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Altrimenti dobbiamo usare &lt;code&gt;switch-client&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Il nostro script è terminato, ora se lanciamo &lt;code&gt;mp&lt;/code&gt; &lt;em&gt;auto-magicamente&lt;/em&gt; ci verrà mostrata la lista dei nostri progetti, selezioniamo quello che vogliamo aprire e voilà! Il nostro script ci ha creato la nuova sessione &lt;code&gt;tmux&lt;/code&gt; ed ha già aperto il nostro editor preferito! &lt;/p&gt;

&lt;p&gt;E se volessimo cambiare progetto? Nessun problema, la sessione corrente verrebbe sostituita con la nuova e lasciata li ad aspettarci!&lt;/p&gt;

&lt;h2&gt;
  
  
  La ciliegina sulla torta
&lt;/h2&gt;

&lt;p&gt;Ovviamente, non mi va ogni volta di aprire il terminale e scrivere &lt;code&gt;mp&lt;/code&gt;, quindi mi sono creato un keymap che ho salvato nel mio &lt;code&gt;~/.tmux.conf&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;bind -r Space run-shell tmux new-window ~/bin/mp&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Nel mio caso il prefix è &lt;code&gt;Ctrl&lt;/code&gt; + &lt;code&gt;Space&lt;/code&gt; quindi mi basta premere &lt;code&gt;Ctrl&lt;/code&gt; + &lt;code&gt;Space&lt;/code&gt; + &lt;code&gt;Space&lt;/code&gt; per fare lo switch ad un'altra sessione.&lt;/p&gt;

&lt;p&gt;Ma vi dirò di più, dato che uso &lt;a href="https://i3wm.org/" rel="noopener noreferrer"&gt;i3&lt;/a&gt;, ho fatto uno script simile (&lt;code&gt;px&lt;/code&gt;) che invece del &lt;code&gt;fzf&lt;/code&gt; utilizza &lt;a href="https://github.com/davatorium/rofi" rel="noopener noreferrer"&gt;rofi&lt;/a&gt; per visualizzare la lista dei progetti, basta questa piccola modifica:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;FOLDER=$(find ${LIST} -mindepth 1 -maxdepth 1 -type d | rofi -dmenu -p "Seleziona il progetto" -font "Monospace 18")&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;ed aggiungere questa riga alla configurazione di &lt;code&gt;i3&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;bindsym $mod+t exec kitty -e $HOME/bin/px&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Così, anche da i3, mi basta premere un tasto per avere il mio progetto aperto e pronto a lavorare!&lt;/p&gt;

&lt;p&gt;Per oggi è tutto, ci vediamo presto! 😎&lt;/p&gt;

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