<?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: JT Ziolo</title>
    <description>The latest articles on DEV Community by JT Ziolo (@jt_ziolo).</description>
    <link>https://dev.to/jt_ziolo</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F848726%2F640b9d0e-37e8-4953-9c6f-5a9b64975a6f.jpg</url>
      <title>DEV Community: JT Ziolo</title>
      <link>https://dev.to/jt_ziolo</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/jt_ziolo"/>
    <language>en</language>
    <item>
      <title>Quickly and Easily Manage Multiple SSH and GPG Keys Across Git Repositories</title>
      <dc:creator>JT Ziolo</dc:creator>
      <pubDate>Thu, 17 Oct 2024 01:58:58 +0000</pubDate>
      <link>https://dev.to/jt_ziolo/quickly-and-easily-check-and-configure-ssh-and-gpg-keys-for-git-repositories-21p6</link>
      <guid>https://dev.to/jt_ziolo/quickly-and-easily-check-and-configure-ssh-and-gpg-keys-for-git-repositories-21p6</guid>
      <description>&lt;p&gt;Git relies on SSH and GPG to ensure secure and authenticated interactions with remote repositories. However, if you use multiple SSH and GPG identities and aren't careful while configuring Git, you can encounter specific issues when running Git commands. I've arrived at the following solution for these issues that I wanted to share since it may work well for others.&lt;/p&gt;

&lt;p&gt;First, a disclaimer: this approach is not intended to replace full-featured identity management tools, and some customization may be required for more complex use cases (e.g., short-lived SSH or GPG keys), but I feel this can be helpful for some developers out there.&lt;/p&gt;

&lt;h2&gt;
  
  
  Understanding SSH and GPG in Git
&lt;/h2&gt;

&lt;p&gt;SSH (Secure Shell) ensures secure communication between your local machine and remote Git repositories. When used with Git, it allows for encrypted data transfer and authentication, making it the preferred choice for interacting with popular hosting platforms like GitHub, GitLab, and Bitbucket &lt;sup id="fnref1"&gt;1&lt;/sup&gt;.&lt;/p&gt;

&lt;p&gt;GPG (GNU Privacy Guard) can be used to digitally sign and verify Git commits. By signing their commits, developers prove their authorship over each commit and combat the threat of commit spoofing. Most version control providers support GPG signatures and offer mechanisms to verify signed commits &lt;sup id="fnref1"&gt;1&lt;/sup&gt; &lt;sup id="fnref2"&gt;2&lt;/sup&gt; &lt;sup id="fnref3"&gt;3&lt;/sup&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Pitfalls of Global SSH and GPG Settings
&lt;/h2&gt;

&lt;p&gt;While global SSH and GPG settings can be convenient, relying solely on them can lead to complications, especially when managing multiple identities &lt;sup id="fnref1"&gt;1&lt;/sup&gt;:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;SSH Key Confusion&lt;/strong&gt;: When multiple SSH keys are configured globally, SSH may attempt to use the wrong key for authentication, resulting in failed login attempts. If authentication fails (e.g., because you mistyped the password), the agent cycles through each key to find a working one, which can be confusing and frustrating.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;GPG Signing Errors&lt;/strong&gt;: If you have multiple GPG keys, Git might use the incorrect key for signing, leading to verification failures when pushing commits.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Configuration Conflicts&lt;/strong&gt;: Setting the wrong GPG or SSH key in your global Git configuration can cause signing failures across all repositories.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Checking the Git Identity with Bash
&lt;/h2&gt;

&lt;p&gt;Before we continue, I'll assume you have already set up Git to require GPG-signed commits globally (this is controlled by the &lt;code&gt;commit.gpgsign&lt;/code&gt; setting) &lt;sup id="fnref4"&gt;4&lt;/sup&gt;.&lt;/p&gt;

&lt;p&gt;Under normal circumstances, it can be challenging to determine which SSH key Git will use for fetch, pull, and push commands. To get around this, we'll force Git to use a specific SSH key file using the &lt;code&gt;core.sshCommand&lt;/code&gt; setting. Here's an example of how you might change this setting from the command line:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git config core.sshCommand &lt;span class="s2"&gt;"ssh -i ~/.ssh/id_ed25519_johndoe_work -o IdentitiesOnly=yes"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Assuming that we have forced Git to use a specific SSH key file, we can quickly check which SSH and GPG keys Git will use with the following (barebones) Bash function. Feel free to edit it to produce neater output.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="k"&gt;function &lt;/span&gt;git-check&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    git config core.sshCommand
    git config user.name
    git config user.email
    git config user.signingkey
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add the function to your &lt;code&gt;~/.bashrc&lt;/code&gt; or &lt;code&gt;~/.bash_profile&lt;/code&gt; file, and source the file using &lt;code&gt;source ~/.bashrc&lt;/code&gt;. You should now be able to navigate to a Git repo on your machine and run &lt;code&gt;git-check&lt;/code&gt; to determine the identity that Git will use for the Git commands you run in that repo.&lt;/p&gt;

&lt;h2&gt;
  
  
  Security Considerations
&lt;/h2&gt;

&lt;p&gt;The information we'll be working with is (in many cases) not as sensitive as you might think.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The filepath to the SSH file doesn't expose the key itself.&lt;/li&gt;
&lt;li&gt;The user name and email settings contain public information for each git commit.&lt;/li&gt;
&lt;li&gt;The GPG signing key fingerprint identifies the public key, and isn't sensitive.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We can prove that the GPG signing key used by Git isn't sensitive with a quick exercise. Go to GitHub and find a popular repo that has GPG-signed commits. If you click the "Verified" badge next to a commit, you'll see a message that includes the GPG key ID. This is the same value as the signing key that we will be using in our Git configuration.&lt;/p&gt;

&lt;h2&gt;
  
  
  Configuring Git for Specific SSH and GPG Keys
&lt;/h2&gt;

&lt;p&gt;You can run the following Git configuration commands to configure the SSH and GPG keys used for each repo, just replace the key file path, signing key, and user settings to match your own:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git config core.sshCommand &lt;span class="s2"&gt;"ssh -i ~/.ssh/id_ed25519_johndoe_work -o IdentitiesOnly=yes"&lt;/span&gt;
git config user.signingkey &lt;span class="s2"&gt;"0123456789ABCDEF"&lt;/span&gt;
git config user.name &lt;span class="s2"&gt;"John Doe"&lt;/span&gt;
git config user.email &lt;span class="s2"&gt;"john.doe@example.com"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To get your GPG signing key, use &lt;code&gt;gpg -K&lt;/code&gt;. In the output, look for the line starting with "sec" (which stands for secret key). The key ID will be displayed after the key type and size, typically in a format like &lt;code&gt;rsa4096/0123456789ABCDEF&lt;/code&gt;. The key listed will likely be longer than the one shown. You only need the last 16 digits of the key but you can use more as long as the ending of the key is included.&lt;/p&gt;

&lt;h3&gt;
  
  
  Automating Local Repository Configuration
&lt;/h3&gt;

&lt;p&gt;You probably don't want to look up your keys and run these commands manually on each repo that needs it. Luckily, it's pretty easy to use Bash to automate this process. Here's an example that can be used to setup a repo for either one of two identities, one for work projects and one for personal projects.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="k"&gt;function &lt;/span&gt;git-setup-work&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    git config core.sshCommand &lt;span class="s2"&gt;"ssh -i ~/.ssh/id_ed25519_johndoe_work -o IdentitiesOnly=yes"&lt;/span&gt;
    git config user.signingkey &lt;span class="s2"&gt;"0123456789ABCDEF"&lt;/span&gt;
    git config user.name &lt;span class="s2"&gt;"John Doe"&lt;/span&gt;
    git config user.email &lt;span class="s2"&gt;"john.doe@company.com"&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;function &lt;/span&gt;git-setup-personal&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    git config core.sshCommand &lt;span class="s2"&gt;"ssh -i ~/.ssh/id_ed25519_johndoe_personal -o IdentitiesOnly=yes"&lt;/span&gt;
    git config user.signingkey &lt;span class="s2"&gt;"0123456789ABCDEF"&lt;/span&gt;
    git config user.name &lt;span class="s2"&gt;"JDNickName"&lt;/span&gt;
    git config user.email &lt;span class="s2"&gt;"jdnickname@gmail.com"&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After defining these functions, source your Bash configuration file and run them to set up your repos as needed.&lt;/p&gt;

&lt;p&gt;By following these practices, you can effectively manage multiple Git identities while avoiding common pitfalls associated with SSH and GPG configurations in Git.&lt;/p&gt;




&lt;ol&gt;

&lt;li id="fn1"&gt;
&lt;p&gt;&lt;a href="https://docs.github.com/en/authentication/managing-commit-signature-verification/telling-git-about-your-signing-key" rel="noopener noreferrer"&gt;https://docs.github.com/en/authentication/managing-commit-signature-verification/telling-git-about-your-signing-key&lt;/a&gt; ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn2"&gt;
&lt;p&gt;&lt;a href="https://docs.gitlab.com/ee/user/project/repository/signed_commits/ssh.html" rel="noopener noreferrer"&gt;https://docs.gitlab.com/ee/user/project/repository/signed_commits/ssh.html&lt;/a&gt; ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn3"&gt;
&lt;p&gt;&lt;a href="https://docs.github.com/en/authentication/managing-commit-signature-verification/about-commit-signature-verification" rel="noopener noreferrer"&gt;https://docs.github.com/en/authentication/managing-commit-signature-verification/about-commit-signature-verification&lt;/a&gt; ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn4"&gt;
&lt;p&gt;&lt;a href="https://git-scm.com/book/en/v2/Git-Tools-Signing-Your-Work" rel="noopener noreferrer"&gt;https://git-scm.com/book/en/v2/Git-Tools-Signing-Your-Work&lt;/a&gt; ↩&lt;/p&gt;
&lt;/li&gt;

&lt;/ol&gt;

</description>
      <category>git</category>
      <category>ssh</category>
      <category>gpg</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Creating a Global .gitignore File as an Extra Line of Defense Against Bad Commits</title>
      <dc:creator>JT Ziolo</dc:creator>
      <pubDate>Sat, 12 Oct 2024 01:12:34 +0000</pubDate>
      <link>https://dev.to/jt_ziolo/how-to-create-a-global-gitignore-file-as-an-extra-precaution-against-committing-secrets-and-unnecessary-files-3hbn</link>
      <guid>https://dev.to/jt_ziolo/how-to-create-a-global-gitignore-file-as-an-extra-precaution-against-committing-secrets-and-unnecessary-files-3hbn</guid>
      <description>&lt;p&gt;Did you know that you can set up the equivalent of a global .gitignore file on your system? It's called an &lt;strong&gt;excludes file&lt;/strong&gt;. You can set which file to use as your excludes file in your global git config under &lt;code&gt;core.excludesFile&lt;/code&gt;. For example, to set the excludes file to the file named &lt;code&gt;.gitexcludes&lt;/code&gt; in your home directory, use: &lt;code&gt;git config --global core.excludesFile "~/.gitexcludes"&lt;/code&gt; (you can also edit your global &lt;code&gt;.gitconfig&lt;/code&gt; file).&lt;/p&gt;

&lt;p&gt;Note that this file is best used as an extra precaution. It should &lt;strong&gt;not&lt;/strong&gt; take the place of setting up .gitignore files in your repos. Your excludes file is local to your system and only works for you, not for collaborators working with you on your repo.&lt;/p&gt;

&lt;h2&gt;
  
  
  My Excludes File and Explanations
&lt;/h2&gt;

&lt;p&gt;Here are the contents of my excludes file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;node_modules
.env.local
.venv/
.vscode
GitIgnore.csproj
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Why I've chosen to ignore these files:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;node_modules&lt;/code&gt;: The local cache containing downloaded Node.js dependencies. Your package.json file and package manager lock files will include all the information required to install your project's dependencies on a given machine. In addition, the contents of &lt;code&gt;node_modules&lt;/code&gt; are often specific to the system that the dependencies were installed on, and the folder can be massive in size.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;.env&lt;/code&gt; or &lt;code&gt;.env.local&lt;/code&gt;: A common location for secrets that must &lt;strong&gt;not&lt;/strong&gt; be committed. The exact files to ignore depends on your project. I use Next.js App Router for most of my web dev projects, where &lt;a href="https://nextjs.org/docs/app/building-your-application/configuring/environment-variables#default-environment-variables" rel="noopener noreferrer"&gt;the convention&lt;/a&gt; is to store secrets in &lt;code&gt;.env.local&lt;/code&gt; while storing other environment variables in other &lt;code&gt;.env&lt;/code&gt; files&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;.venv/&lt;/code&gt;: This is what I typically name my virtual environment directory when working with Python. Virtual environments should be created and activated separately on each collaborator's machine, and the directory should not be committed. Instead, commit just the requirements.txt file and use it to install pip packages inside the virtual environment.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;.vscode&lt;/code&gt;: This directory includes things specific to the VSCode IDE (my preferred IDE), like folder-specific user settings and extension files.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;GitIgnore.csproj&lt;/code&gt;: This serves a special purpose in that it allows me to alter the build process for C# project files in repos that I'm working with without needing to worry about accidentally committing these changes later. For example, when one of my C# projects relies on a different C# project as a project dependency, running &lt;code&gt;dotnet build&lt;/code&gt; on my C# project will also build the dependency. If the dependency includes custom build steps, then those steps can cause my build to fail, but I can avoid this issue by copying the original project file to GitIgnore.csproj and removing those custom steps. This sort of scheme could also be useful in other languages that have their own project or package files.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>tutorial</category>
      <category>git</category>
      <category>security</category>
    </item>
    <item>
      <title>Full NeoVim Config and Explanations for VSCode-NeoVim Users</title>
      <dc:creator>JT Ziolo</dc:creator>
      <pubDate>Wed, 12 Jul 2023 01:24:58 +0000</pubDate>
      <link>https://dev.to/jt_ziolo/full-neovim-config-and-explanations-for-vscode-neovim-users-2did</link>
      <guid>https://dev.to/jt_ziolo/full-neovim-config-and-explanations-for-vscode-neovim-users-2did</guid>
      <description>&lt;p&gt;Since around February of this year (2023), I've been doing most of my coding using the VSCode-NeoVim extension. For a while now, I've been interested in seeing what a plugin-enhanced NeoVim has to offer in terms of a full IDE experience. Unfortunately, every time I've tried to set up something like NvChad or LunarNvim, I've run into the same set of problems:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;I don't need all of the plugins.&lt;/li&gt;
&lt;li&gt;I don't know what many of the plugins are for.&lt;/li&gt;
&lt;li&gt;I don't agree with the keybinds (they are almost always completely different than equivalent actions I've memorized when working in VSCode).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Even though I can fix all of the above, I don't want to spend a week doing that when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;I'm not the person who set up the plugins.&lt;/li&gt;
&lt;li&gt;The NeoVim config code is split up across multiple files for some reason.&lt;/li&gt;
&lt;li&gt;I have a working code editor already.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So until recently, I just stuck with VSCode-NeoVim. However, I recently had a breakthrough. After many phind searches and going through a lot of stack overflow posts of varying quality, I figured out how to set up NeoVim to include all the essential features of an IDE: a file browser, command palette, autocomplete, code actions, etc.&lt;/p&gt;

&lt;p&gt;While doing so, I split up my init.lua file so that NeoVim will still work in VSCode-NeoVim.&lt;/p&gt;

&lt;h2&gt;
  
  
  My Configuration
&lt;/h2&gt;

&lt;p&gt;Here is a gist containing my current init.lua file: &lt;a href="https://gist.github.com/jt-ziolo/cac64c2d17d6036fc6a61a26898b91b2" rel="noopener noreferrer"&gt;https://gist.github.com/jt-ziolo/cac64c2d17d6036fc6a61a26898b91b2&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwr1jwzmekkexm5g300go.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwr1jwzmekkexm5g300go.png" alt="My NeoVim configuration, shown for a NextJS project" width="800" height="429"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here is a barebones example which shows how the init.lua file is set up:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight lua"&gt;&lt;code&gt;&lt;span class="n"&gt;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;-- Make sure to set `mapleader` before lazy so your mappings are correct&lt;/span&gt;

&lt;span class="c1"&gt;-- Set up lazy.nvim (the plugin manager)&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="c1"&gt;-- latest stable release&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="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;g&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;vscode&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
    &lt;span class="c1"&gt;-------------------------------------------------------------------&lt;/span&gt;
    &lt;span class="c1"&gt;-- The following applies ONLY for VSCode-NeoVim&lt;/span&gt;
    &lt;span class="c1"&gt;-- Everything under require("lazy") will be a subset of what is&lt;/span&gt;
    &lt;span class="c1"&gt;-- included in the settings for ordinary NeoVim&lt;/span&gt;
    &lt;span class="c1"&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;"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;-- Plugin installs, which either just point to the github repo&lt;/span&gt;
        &lt;span class="c1"&gt;-- or which are based on lazy.nvim-specific instructions from&lt;/span&gt;
        &lt;span class="c1"&gt;-- the repo&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;

    &lt;span class="c1"&gt;-- Some settings can go here&lt;/span&gt;
    &lt;span class="c1"&gt;-- but I'm not sure what yet&lt;/span&gt;

    &lt;span class="c1"&gt;-- Requires&lt;/span&gt;
    &lt;span class="c1"&gt;-----------&lt;/span&gt;
    &lt;span class="c1"&gt;-- ex: require("hop").setup({})&lt;/span&gt;
    &lt;span class="c1"&gt;-- You will likely not put anything here&lt;/span&gt;
    &lt;span class="c1"&gt;-- ...&lt;/span&gt;

    &lt;span class="c1"&gt;-- Keybinds&lt;/span&gt;
    &lt;span class="c1"&gt;-----------&lt;/span&gt;
    &lt;span class="c1"&gt;-- ex: vim.keymap.set("n", "n", "nzz", {})&lt;/span&gt;
    &lt;span class="c1"&gt;-- ...&lt;/span&gt;
&lt;span class="k"&gt;else&lt;/span&gt;
    &lt;span class="c1"&gt;-------------------------------------------------------------------&lt;/span&gt;
    &lt;span class="c1"&gt;-- The following applies ONLY for ordinary Neovim outside of VSCode&lt;/span&gt;
    &lt;span class="c1"&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;"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;-- Plugin installs, which either just point to the github repo&lt;/span&gt;
        &lt;span class="c1"&gt;-- or which are based on lazy.nvim-specific instructions from&lt;/span&gt;
        &lt;span class="c1"&gt;-- the repo. The difference here is that you include plugins&lt;/span&gt;
        &lt;span class="c1"&gt;-- related to LSP functionality, code completion, etc.&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;

    &lt;span class="c1"&gt;-- Some settings can go here&lt;/span&gt;
    &lt;span class="c1"&gt;-- ex: vim.diagnostic.config({ virtual_text = false })&lt;/span&gt;

    &lt;span class="c1"&gt;-- Requires&lt;/span&gt;
    &lt;span class="c1"&gt;-----------&lt;/span&gt;
    &lt;span class="c1"&gt;-- ex: require("onedark").load()&lt;/span&gt;
    &lt;span class="c1"&gt;-- ...&lt;/span&gt;

    &lt;span class="c1"&gt;-- Keybinds&lt;/span&gt;
    &lt;span class="c1"&gt;-----------&lt;/span&gt;
    &lt;span class="c1"&gt;-- ex: vim.keymap.set("n", "&amp;lt;leader&amp;gt;i", "&amp;lt;cmd&amp;gt;Neoformat&amp;lt;CR&amp;gt;", { desc = "Neoformat" })&lt;/span&gt;
    &lt;span class="c1"&gt;-- ...&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="c1"&gt;-------------------------------------------------------------------&lt;/span&gt;
&lt;span class="c1"&gt;-- The following applies for BOTH VSCode and ordinary Neovim&lt;/span&gt;
&lt;span class="c1"&gt;-- Note that we cannot call require("lazy").setup here,&lt;/span&gt;
&lt;span class="c1"&gt;-- so load your plugins in the prior two sections&lt;/span&gt;
&lt;span class="c1"&gt;-------------------------------------------------------------------&lt;/span&gt;

&lt;span class="c1"&gt;-- Requires&lt;/span&gt;
&lt;span class="c1"&gt;-----------&lt;/span&gt;
&lt;span class="c1"&gt;-- ex: require("hop").setup({})&lt;/span&gt;
&lt;span class="c1"&gt;-- ...&lt;/span&gt;

&lt;span class="c1"&gt;-- Keybinds&lt;/span&gt;
&lt;span class="c1"&gt;-----------&lt;/span&gt;
&lt;span class="c1"&gt;-- ex: vim.keymap.set("n", "n", "nzz", {})&lt;/span&gt;
&lt;span class="c1"&gt;-- ...&lt;/span&gt;

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

&lt;/div&gt;



&lt;h2&gt;
  
  
  What the Plugins Do
&lt;/h2&gt;

&lt;p&gt;First off, let's define what "LSP" means:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The Language Server Protocol (LSP) defines the protocol used between an editor or IDE and a language server that provides language features like auto complete, go to definition, find all references etc. (&lt;a href="https://microsoft.github.io/language-server-protocol/" rel="noopener noreferrer"&gt;https://microsoft.github.io/language-server-protocol/&lt;/a&gt;)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Many of the plugins that I will list are focused on LSP management and integration, so knowing what is meant by LSP will help you as you read through plugin documentation.&lt;/p&gt;

&lt;p&gt;Here is a list of the important plugins and what they do, in terms that someone coming from VSCode could understand. Note that I have listed just the particular plugin that I'm currently using, but multiple options may exist. For example: snippy is just one option for adding a snippet system, other options I know of are vsnip, ultisnips, and luasnip and I'm certain that there are others out there.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Repo&lt;/th&gt;
&lt;th&gt;What It Does&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/dcampos/nvim-snippy" rel="noopener noreferrer"&gt;"dcampos/nvim-snippy"&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Provides a snippet system&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/dcampos/cmp-snippy" rel="noopener noreferrer"&gt;"dcampos/cmp-snippy"&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Integrates the snippet system with suggestions/autocomplete as you type&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/hrsh7th/cmp-cmdline" rel="noopener noreferrer"&gt;"hrsh7th/cmp-cmdline"&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Suggestions/autocomplete for NeoVim commands as you type (e.g. :write)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/hrsh7th/cmp-buffer" rel="noopener noreferrer"&gt;"hrsh7th/cmp-buffer"&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Suggestions/autocomplete for searches (/ and ?) as you type&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/hrsh7th/cmp-nvim-lsp" rel="noopener noreferrer"&gt;"hrsh7th/cmp-nvim-lsp"&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Dependency for some plugins that interface with the LSP&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/rsh7th/nvim-cmp" rel="noopener noreferrer"&gt;"rsh7th/nvim-cmp"&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Dependency for previous 3 plugins&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/jay-babu/mason-null-ls.nvim" rel="noopener noreferrer"&gt;"jay-babu/mason-null-ls.nvim"&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Sets up Mason to work with null-ls&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/jose-elias-alvarez/null-ls.nvim" rel="noopener noreferrer"&gt;"jose-elias-alvarez/null-ls.nvim&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Dependency that is required by plugins which need to access code completion, warnings/errors (diagnostics), code actions, and related suggestion functionality&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/neovim/nvim-lspconfig" rel="noopener noreferrer"&gt;"neovim/nvim-lspconfig"&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Dependency that allows code completion, warnings/errors (diagnostics), code actions, and related suggestion functionality. Its an official neovim plugin.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/nvim-lua/plenary.nvim" rel="noopener noreferrer"&gt;"nvim-lua/plenary.nvim"&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;A library of helper functions for neovim that is required by many plugins.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/nvim-telescope/telescope.nvim" rel="noopener noreferrer"&gt;"nvim-telescope/telescope.nvim"&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Think of it as a replacement for the command palette.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/nvim-tree/nvim-tree.lua" rel="noopener noreferrer"&gt;"nvim-tree/nvim-tree.lua"&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;A replacement for the explorer menu.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/nvim-treesitter/nvim-treesitter" rel="noopener noreferrer"&gt;"nvim-treesitter/nvim-treesitter"&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Dependency which manages and provides access to the syntax tree for the current file, which is needed by plugins for things like detecting syntax errors, figuring out where an editor symbol is located in files, etc.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.cm/sbdchd/neoformat" rel="noopener noreferrer"&gt;"sbdchd/neoformat"&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Formats files using any formatters you have installed.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/williamboman/mason-lspconfig.nvim" rel="noopener noreferrer"&gt;"williamboman/mason-lspconfig.nvim"&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Allows the NeoVim LSP service to "see" the LSPs installed via Mason.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/williamboman/mason.nvim" rel="noopener noreferrer"&gt;"williamboman/mason.nvim"&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Used to install/update formatters, LSPs, debuggers, and linters. Those things won't actually work without you installing other plugins, though.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/akinsho/bufferline.nvim" rel="noopener noreferrer"&gt;"akinsho/bufferline.nvim"&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;The tab bar on top of your editor, showing open tabs (buffers)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/folke/zen-mode.nvim" rel="noopener noreferrer"&gt;"folke/zen-mode.nvim"&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Zen mode&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/nvim-lualine/lualine.nvim" rel="noopener noreferrer"&gt;"nvim-lualine/lualine.nvim"&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;The bottom bar that shows your current mode, the file name, scroll percentage, line/character number, git status, etc.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/nvim-tree/nvim-web-devicons" rel="noopener noreferrer"&gt;"nvim-tree/nvim-web-devicons"&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Dependency that is used to provide icons next to files for nvim-tree, and which is used by many other plugins as a source of devicons.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/nvimdev/lspsaga.nvim" rel="noopener noreferrer"&gt;"nvimdev/lspsaga.nvim"&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Provides a better experience for things like renaming symbols, getting a floating terminal, showing a menu for the symbol under the cursor, etc. I use it mainly for navigating errors/warnings (diagnotics) with quick access to code actions. The documentation is full of screenshots: &lt;a href="https://dev.neovim.pro/lspsaga/" rel="noopener noreferrer"&gt;https://dev.neovim.pro/lspsaga/&lt;/a&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/onsails/lspkind-nvim" rel="noopener noreferrer"&gt;"onsails/lspkind-nvim"&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Adds symbols to the suggestion/autocomplete window&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/tpope/vim-eunuch" rel="noopener noreferrer"&gt;"tpope/vim-eunuch"&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;It lets you change the currently opened file, including renaming, changing permissions, deletion, etc. I'm not sure why it's called eunuch either, but it's made by tpope, and everything he makes is gold.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/windwp/nvim-autopairs" rel="noopener noreferrer"&gt;"windwp/nvim-autopairs"&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Auto-closes quotes, braces, parentheses, etc.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/windwp/nvim-ts-autotag" rel="noopener noreferrer"&gt;"windwp/nvim-ts-autotag"&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Auto-closes HTML, XML, and other markup tags as you type them.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;I hope that this post helps you understand the role of each plugin, while avoiding the annoying experience of searching around for answers about what X error message means, figuring out what a plugin does, reading through pedantic responses about how it should be so clear and obvious to do something based on NeoVim's documentation... etc.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why is It So Complicated?
&lt;/h2&gt;

&lt;p&gt;One concept that some readers may struggle with (and which I had also struggled with) is why so many plugins are needed to get basic IDE features.&lt;/p&gt;

&lt;p&gt;NeoVim, like vim, is minimalistic in its design. Out of the box (without any plugins installed), NeoVim is a very simple editor with modal text editing capabilities, sort of like Notepad++. Maybe this is all you want or need. For example, you don't need those IDE features if you only install NeoVim as a dependency for VSCode-NeoVim (nor would you want it, since they would probably conflict with VSCode).&lt;/p&gt;

&lt;p&gt;However, if you do want IDE features, NeoVim's plugin capabilities and ecosystem are mature enough that you can add them. This allows you to set up a custom configuration tailored to your use, without the bloat of unused features or plugins.&lt;/p&gt;

</description>
      <category>neovim</category>
      <category>vim</category>
      <category>lua</category>
      <category>vscode</category>
    </item>
  </channel>
</rss>
