479 lines
40 KiB
HTML
479 lines
40 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="en" dir="auto">
|
||
|
||
<head><meta charset="utf-8">
|
||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||
<meta name="robots" content="index, follow">
|
||
<title>Neovim Subtitute Magic | Norm-working Packets 💾</title>
|
||
<meta name="keywords" content="snippet, neovim">
|
||
<meta name="description" content="I was able to speed up some of my workflows by learning how to search and replace specifics in Neovim!">
|
||
<meta name="author" content="Me">
|
||
<link rel="canonical" href="../posts/find_and_replace_in_neovim.html">
|
||
<link crossorigin="anonymous" href="../assets/css/stylesheet.b609c58d5c11bb90b1a54e04005d74ad1ddf22165eb79f5533967e57df9c3b50.css" integrity="sha256-tgnFjVwRu5CxpU4EAF10rR3fIhZet59VM5Z+V9+cO1A=" rel="preload stylesheet" as="style">
|
||
<link rel="icon" href="../favicon.ico">
|
||
<link rel="icon" type="image/png" sizes="16x16" href="../favicon-16x16.png">
|
||
<link rel="icon" type="image/png" sizes="32x32" href="../rsmsncircles.ico">
|
||
<link rel="apple-touch-icon" href="../apple-touch-icon.png">
|
||
<link rel="mask-icon" href="../safari-pinned-tab.svg">
|
||
<meta name="theme-color" content="#2e2e33">
|
||
<meta name="msapplication-TileColor" content="#2e2e33">
|
||
<link rel="alternate" hreflang="en" href="../posts/find_and_replace_in_neovim.html">
|
||
<noscript>
|
||
<style>
|
||
#theme-toggle,
|
||
.top-link {
|
||
display: none;
|
||
}
|
||
|
||
</style>
|
||
</noscript><meta property="og:title" content="Neovim Subtitute Magic" />
|
||
<meta property="og:description" content="I was able to speed up some of my workflows by learning how to search and replace specifics in Neovim!" />
|
||
<meta property="og:type" content="article" />
|
||
<meta property="og:url" content="/posts/find_and_replace_in_neovim.html" />
|
||
<meta property="og:image" content="/nvim_searching_replacing.png" /><meta property="article:section" content="posts" />
|
||
<meta property="article:published_time" content="2023-11-15T08:08:49-05:00" />
|
||
<meta property="article:modified_time" content="2023-11-15T08:08:49-05:00" /><meta property="og:site_name" content="Norm-working Packets" />
|
||
|
||
<meta name="twitter:card" content="summary_large_image" />
|
||
<meta name="twitter:image" content="/nvim_searching_replacing.png" />
|
||
<meta name="twitter:title" content="Neovim Subtitute Magic"/>
|
||
<meta name="twitter:description" content="I was able to speed up some of my workflows by learning how to search and replace specifics in Neovim!"/>
|
||
|
||
|
||
<script type="application/ld+json">
|
||
{
|
||
"@context": "https://schema.org",
|
||
"@type": "BreadcrumbList",
|
||
"itemListElement": [
|
||
{
|
||
"@type": "ListItem",
|
||
"position": 1 ,
|
||
"name": "Posts",
|
||
"item": "/posts.html"
|
||
}
|
||
{
|
||
"@type": "ListItem",
|
||
"position": 1 ,
|
||
"name": "Neovim Subtitute Magic",
|
||
"item": "/posts/find_and_replace_in_neovim.html"
|
||
}
|
||
]
|
||
}
|
||
</script>
|
||
<script type="application/ld+json">
|
||
{
|
||
"@context": "https://schema.org",
|
||
"@type": "BlogPosting",
|
||
"headline": "Neovim Subtitute Magic",
|
||
"name": "Neovim Subtitute Magic",
|
||
"description": "I was able to speed up some of my workflows by learning how to search and replace specifics in Neovim!",
|
||
"keywords": [
|
||
"snippet", "neovim"
|
||
],
|
||
"articleBody": "This week, I’ve had to make some changes to an automation we had setup for a customer in Workato. The original recipe was made by a co-worker with a bunch of javascript nodes. Even though I’m customer facing and generally not considered a technical employee, I knew the engineer who worked on this was swamped, so I decided to jump in.\nIn order to greatly reduce the number of nodes needed in the single recipe, I created a list of dictionaries in python (with one of the values being another list!) and a quick for loop to grab all the appropriate elements from the various dictionaries. I had thankfully already copied all the JS nodes to a single file for easy reference and retrieval. That one file had over 8,000 lines, and I needed to replace all the javascript elements with python.\nHere’s one node of Javascript that I was working with:\n// @param input fields supplied in the recipe step, as an object // @return object matching the output schema // Eg: Code for returning time zone for an IP address exports.main = async ({ user_email }) =\u003e { let all_domains = [ 'domain_one', 'domain_two', 'domain_three', 'domain_four', 'domain_five', 'domain_six', ] let user_domain = user_email.slice(user_email.indexOf('@')); let domain_found = all_domains.indexOf(user_domain) \u003e -1; return { domain_found }; } Most nodes were very similar, all except that their all_domains array had anywhere from 1 to 500+ elements. Thanks to the neovim plugin Telescope Cmdline by Jon Arrien, you can very easily see your past history of Neovim commands. I’ve gone back through and pulled out a few special ones that helped and that I was very surprised how well they worked. I don’t claim that this was the fastest or best way to clean up a large file with repeating functions, but I definitely learned a bunch about searching-and-replacing in Neovim, and any future needs for this will be way faster! One thing that has been really helpful with Neovim is that as you run the first portion of all the commands below, Neovim should highlight what it finds. This is really helpful for real-time debugging of your regex.\nCommands and Quick Explanations Command: :g/\\//+2/d\nExplanation: The g in the command stands for global (hint, run :h :g in vim!) and will search across the entire buffer you have open. In this command I’m looking for all Javascript single-line comments. Since the forward slash is a special character for neovim, you need to escape it with a backwards slash, hence the odd looking \\/. The second forward slash is the next parameter neovim is looking for, and by adding +{num}, you can search for the pattern plus a number of lines. Closing out the command (again, next parameter comes after the forward slash) with d for delete will then delete everything with you searched for, plus the additional number of lines.\nBonus: if you wanted to make sure that you only pulled lines that began with a comment, you’d add a carrot to the beginning of the command. :g/^\\//+2/d\nCommand: :%s/let all_domains = /\"domains\" : /g\nExplanation: Moving on from g to s, the s here stands for substitute. There’s one big difference in using g and s, though. While g will search globally, a singular s will only search on your current line. To search the entire file/buffer, you need to include the percent character before the s. The rest of this is fairly straight forward, I am searching for the declaration of a javascript variable and then substituting it with a python dictionary key. Since both javascript and python declare arrays with square brackets, I wanted to make sure I kept that after the substitution. Lastly, unless you only want the subsitute to change the first occurrence of what it finds, you’ll need to close out the command with the g flag. Neovim’s docs say:\n[g] Replace all occurrences in the line. Without this argument, replacement occurs only for the first occurrence in each line. If the 'gdefault' option is on, this flag is on by default and the [g] argument switches it off. Command: :%s/^exports.main.*/{ \"uuid\" :/g\nExplanation: Really similar to the above command, but in this case, there are no characters I needed to save post-substitution. We already know what %s does, so the pattern I’m looking for is all lines that start with exports.main. Since I don’t need anything after that start of the line, I included .* which looks for any character until the end of the line. After the pattern I write out what I need to replace it with, which is the first portion of the dictionaries I need. Finally, we close it out with a global change so it changes it everywhere.\nCommand: :%s/return.*/], Explanation: Finally, I used this one to close out the domains list/array that I’m using.\nBonus Command: %s/\"props\": \\[\\(.*\\)\\]\\,/\"props\" : \\1,/g\nExplanation: I won’t go over all the characters and regex commands as I’m reusing a lot of them from the above commands. What is different here is that I’ve lumped the wild card in parenthesis like so: (.*\\). Now, I can call back what is pulled by using \\1. The command above is looking for a dictionary item with a list as the value. I didn’t need the list, just a string, since all values in my list of dictionaries are single values. By searching for \"props\": [ string ], and using the \\1, I’m able to keep the string intact and the result is \"props\": string,.\nThis was the milestone command to learn for me and helped unlock so much potential in my brain for other use cases. For all the other commands I’ve gone over above, I’m fairly simply just replacing characters I no longer need that exist either before or after characters I do need. Now that I can keep strings intact for substitutions, I bet I could revisit all the above commands and make them even more efficient.\nWhat I’d like to learn next is if I can use an “or” statement in the regex. Let’s say I have the same situation as above - a list of dictionaries with some dict values being a list. Well, if the lists are all formatted differently, some on new lines, others on a single line, can I select both in a single command? Something like: :%s/\"domains\": \\[\\(.* OR \\n\\)/.\nThat will be a post for another time! Let me know on Mastodon if you have any other Neovim search and replace tips and tricks that have become invaluable to your workflow. I’m always amazed and impressed with this community and how differently people are able to use the same tool.\nBy the way, here’s the final output of running the above commands on the sample code above, converted to Python.\nmappings = { 'uuid': \"1234-1234-1234-1234\", 'domains': [ 'domain_one', 'domain_two', 'domain_three', 'domain_four', 'domain_five', 'domain_six', ], 'props': 'property-mapping', } Resources Here are some various links of resources that I found helpful when learning about the above commands. I’m assuming you’ve already read through anything in Neovim’s Helpdocs (:h), but sometimes you need a different take and explanation.\nVim Search, Find \u0026 Replace - Reddit Search Across Multiple Lines - Vim Tips Wiki Vim Search and Replace with Examples - The Valuable Dev Removing Specific Characters in Vim - Stack Overflow ",
|
||
"wordCount" : "1221",
|
||
"inLanguage": "en",
|
||
"image":"/nvim_searching_replacing.png","datePublished": "2023-11-15T08:08:49-05:00",
|
||
"dateModified": "2023-11-15T08:08:49-05:00",
|
||
"author":{
|
||
"@type": "Person",
|
||
"name": "Me"
|
||
},
|
||
"mainEntityOfPage": {
|
||
"@type": "WebPage",
|
||
"@id": "/posts/find_and_replace_in_neovim.html"
|
||
},
|
||
"publisher": {
|
||
"@type": "Organization",
|
||
"name": "Norm-working Packets 💾",
|
||
"logo": {
|
||
"@type": "ImageObject",
|
||
"url": "/favicon.ico"
|
||
}
|
||
}
|
||
}
|
||
</script>
|
||
</head>
|
||
|
||
<body class=" dark" id="top">
|
||
<script>
|
||
if (localStorage.getItem("pref-theme") === "light") {
|
||
document.body.classList.remove('dark')
|
||
}
|
||
|
||
</script>
|
||
|
||
<header class="header">
|
||
<nav class="nav">
|
||
<div class="logo">
|
||
<a href="../" accesskey="h" title="Norm-working Packets 💾 (Alt + H)">Norm-working Packets 💾</a>
|
||
<div class="logo-switches">
|
||
<button id="theme-toggle" accesskey="t" title="(Alt + T)">
|
||
<svg id="moon" xmlns="http://www.w3.org/2000/svg" width="24" height="18" viewBox="0 0 24 24"
|
||
fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"
|
||
stroke-linejoin="round">
|
||
<path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"></path>
|
||
</svg>
|
||
<svg id="sun" xmlns="http://www.w3.org/2000/svg" width="24" height="18" viewBox="0 0 24 24"
|
||
fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"
|
||
stroke-linejoin="round">
|
||
<circle cx="12" cy="12" r="5"></circle>
|
||
<line x1="12" y1="1" x2="12" y2="3"></line>
|
||
<line x1="12" y1="21" x2="12" y2="23"></line>
|
||
<line x1="4.22" y1="4.22" x2="5.64" y2="5.64"></line>
|
||
<line x1="18.36" y1="18.36" x2="19.78" y2="19.78"></line>
|
||
<line x1="1" y1="12" x2="3" y2="12"></line>
|
||
<line x1="21" y1="12" x2="23" y2="12"></line>
|
||
<line x1="4.22" y1="19.78" x2="5.64" y2="18.36"></line>
|
||
<line x1="18.36" y1="5.64" x2="19.78" y2="4.22"></line>
|
||
</svg>
|
||
</button>
|
||
<ul class="lang-switch"><li>|</li>
|
||
</ul>
|
||
</div>
|
||
</div>
|
||
<ul id="menu">
|
||
<li>
|
||
<a href="../posts.html" title="Posts">
|
||
<span>Posts</span>
|
||
</a>
|
||
</li>
|
||
</ul>
|
||
</nav>
|
||
</header>
|
||
<main class="main">
|
||
|
||
<article class="post-single">
|
||
<header class="post-header">
|
||
<div class="breadcrumbs"><a href="../">Home</a> » <a href="../posts.html">Posts</a></div>
|
||
<h1 class="post-title entry-hint-parent">
|
||
Neovim Subtitute Magic
|
||
</h1>
|
||
<div class="post-description">
|
||
I was able to speed up some of my workflows by learning how to search and replace specifics in Neovim!
|
||
</div>
|
||
<div class="post-meta"><span title='2023-11-15 08:08:49 -0500 EST'>November 15, 2023</span> · 6 min · 1221 words · Me
|
||
|
||
</div>
|
||
</header>
|
||
<div class="post-content"><p>This week, I’ve had to make some changes to an automation we had setup for a customer in <a href="https://workato.com">Workato</a>. The
|
||
original recipe was made by a co-worker with a bunch of javascript nodes. Even though I’m customer facing and generally not
|
||
considered a technical employee, I knew the engineer who worked on this was swamped, so I decided to jump in.</p>
|
||
<p>In order to greatly reduce the number of nodes needed in the single recipe, I created a list of dictionaries in python (with
|
||
one of the values being another list!) and a quick for loop to grab all the appropriate elements from the various
|
||
dictionaries. I had thankfully already copied all the JS nodes to a single file for easy reference and retrieval. That one
|
||
file had over 8,000 lines, and I needed to replace all the javascript elements with python.</p>
|
||
<p>Here’s one node of Javascript that I was working with:</p>
|
||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span><span style="color:#75715e">// @param input fields supplied in the recipe step, as an object
|
||
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">// @return object matching the output schema
|
||
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">// Eg: Code for returning time zone for an IP address
|
||
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>
|
||
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">exports</span>.<span style="color:#a6e22e">main</span> <span style="color:#f92672">=</span> <span style="color:#66d9ef">async</span> ({ <span style="color:#a6e22e">user_email</span> }) => {
|
||
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">let</span> <span style="color:#a6e22e">all_domains</span> <span style="color:#f92672">=</span> [
|
||
</span></span><span style="display:flex;"><span> <span style="color:#e6db74">'domain_one'</span>,
|
||
</span></span><span style="display:flex;"><span> <span style="color:#e6db74">'domain_two'</span>,
|
||
</span></span><span style="display:flex;"><span> <span style="color:#e6db74">'domain_three'</span>,
|
||
</span></span><span style="display:flex;"><span> <span style="color:#e6db74">'domain_four'</span>,
|
||
</span></span><span style="display:flex;"><span> <span style="color:#e6db74">'domain_five'</span>,
|
||
</span></span><span style="display:flex;"><span> <span style="color:#e6db74">'domain_six'</span>,
|
||
</span></span><span style="display:flex;"><span>]
|
||
</span></span><span style="display:flex;"><span>
|
||
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">let</span> <span style="color:#a6e22e">user_domain</span> <span style="color:#f92672">=</span> <span style="color:#a6e22e">user_email</span>.<span style="color:#a6e22e">slice</span>(<span style="color:#a6e22e">user_email</span>.<span style="color:#a6e22e">indexOf</span>(<span style="color:#e6db74">'@'</span>));
|
||
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">let</span> <span style="color:#a6e22e">domain_found</span> <span style="color:#f92672">=</span> <span style="color:#a6e22e">all_domains</span>.<span style="color:#a6e22e">indexOf</span>(<span style="color:#a6e22e">user_domain</span>) <span style="color:#f92672">></span> <span style="color:#f92672">-</span><span style="color:#ae81ff">1</span>;
|
||
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">return</span> { <span style="color:#a6e22e">domain_found</span> };
|
||
</span></span><span style="display:flex;"><span>}
|
||
</span></span></code></pre></div><p>Most nodes were very similar, all except that their <code>all_domains</code> array had anywhere from 1 to 500+ elements. Thanks to the
|
||
neovim plugin <a href="https://github.com/jonarrien/telescope-cmdline.nvim">Telescope Cmdline</a> by <a href="https://github.com/jonarrien">Jon Arrien</a>,
|
||
you can very easily see your past history of Neovim commands. I’ve gone back through and pulled out a few special ones that
|
||
helped and that I was very surprised how well they worked. I don’t claim that this was the fastest or best way to clean up a
|
||
large file with repeating functions, but I definitely learned a bunch about searching-and-replacing in Neovim, and any future
|
||
needs for this will be <em>way</em> faster! One thing that has been really helpful with Neovim is that as you run the first portion
|
||
of all the commands below, Neovim should highlight what it finds. This is really helpful for real-time debugging of your
|
||
regex.</p>
|
||
<h2 id="commands-and-quick-explanations">Commands and Quick Explanations<a hidden class="anchor" aria-hidden="true" href="#commands-and-quick-explanations">#</a></h2>
|
||
<hr>
|
||
<p><strong>Command:</strong> <code>:g/\//+2/d</code></p>
|
||
<p><strong>Explanation:</strong> The g in the command stands for global (hint, run <code>:h :g</code> in vim!) and will search across the entire buffer
|
||
you have open. In this command I’m looking for all Javascript single-line comments. Since the forward slash is a special
|
||
character for neovim, you need to escape it with a backwards slash, hence the odd looking <code>\/</code>. The second forward slash is
|
||
the next parameter neovim is looking for, and by adding +{num}, you can search for the pattern plus a number of lines.
|
||
Closing out the command (again, next parameter comes after the forward slash) with <code>d</code> for delete will then delete everything
|
||
with you searched for, plus the additional number of lines.</p>
|
||
<p>Bonus: if you wanted to make sure that you only pulled lines that <em>began</em> with a comment, you’d add a carrot to the beginning
|
||
of the command. <code>:g/^\//+2/d</code></p>
|
||
<hr>
|
||
<p><strong>Command:</strong> <code>:%s/let all_domains = /"domains" : /g</code></p>
|
||
<p><strong>Explanation:</strong> Moving on from <code>g</code> to <code>s</code>, the <code>s</code> here stands for substitute. There’s one big difference in using <code>g</code> and
|
||
<code>s</code>, though. While <code>g</code> will search globally, a singular <code>s</code> will only search on your current line. To search the entire
|
||
file/buffer, you need to include the percent character before the <code>s</code>. The rest of this is fairly straight forward, I am
|
||
searching for the declaration of a javascript variable and then substituting it with a python dictionary key. Since both
|
||
javascript and python declare arrays with square brackets, I wanted to make sure I kept that after the substitution. Lastly,
|
||
unless you only want the subsitute to change the first occurrence of what it finds, you’ll need to close out the command with
|
||
the <code>g</code> flag. Neovim’s docs say:</p>
|
||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-markdown" data-lang="markdown"><span style="display:flex;"><span>[g] Replace all occurrences in the line. Without this argument,
|
||
</span></span><span style="display:flex;"><span> replacement occurs only for the first occurrence in each line. If the
|
||
</span></span><span style="display:flex;"><span> 'gdefault' option is on, this flag is on by default and the [g]
|
||
</span></span><span style="display:flex;"><span> argument switches it off.
|
||
</span></span></code></pre></div><hr>
|
||
<p><strong>Command:</strong> <code>:%s/^exports.main.*/{ "uuid" :/g</code></p>
|
||
<p><strong>Explanation:</strong> Really similar to the above command, but in this case, there are no characters I needed to save
|
||
post-substitution. We already know what <code>%s</code> does, so the pattern I’m looking for is all lines that start with
|
||
<code>exports.main</code>. Since I don’t need anything after that start of the line, I included <code>.*</code> which looks for any character until
|
||
the end of the line. After the pattern I write out what I need to replace it with, which is the first portion of the
|
||
dictionaries I need. Finally, we close it out with a global change so it changes it everywhere.</p>
|
||
<p><strong>Command:</strong> <code>:%s/return.*/],</code>
|
||
<strong>Explanation:</strong> Finally, I used this one to close out the domains list/array that I’m using.</p>
|
||
<hr>
|
||
<p><strong>Bonus Command:</strong> <code>%s/"props": \[\(.*\)\]\,/"props" : \1,/g</code></p>
|
||
<p><strong>Explanation:</strong> I won’t go over all the characters and regex commands as I’m reusing a lot of them from the above commands.
|
||
What is different here is that I’ve lumped the wild card in parenthesis like so: <code>(.*\)</code>. Now, I can call back what is
|
||
pulled by using <code>\1</code>. The command above is looking for a dictionary item with a list as the value. I didn’t need the list,
|
||
just a string, since all values in my list of dictionaries are single values. By searching for <code>"props": [ string ],</code> and
|
||
using the <code>\1</code>, I’m able to keep the string intact and the result is <code>"props": string,</code>.</p>
|
||
<p>This was the milestone command to learn for me and helped unlock so much potential in my brain for other use
|
||
cases. For all the other commands I’ve gone over above, I’m fairly simply just replacing characters I no longer need that
|
||
exist either <em>before or after</em> characters I do need. Now that I can keep strings intact for substitutions, I bet I could
|
||
revisit all the above commands and make them even more efficient.</p>
|
||
<p>What I’d like to learn next is if I can use an “or” statement in the regex. Let’s say I have the same situation as above - a
|
||
list of dictionaries with some dict values being a list. Well, if the lists are all formatted differently, some on new lines,
|
||
others on a single line, can I select both in a single command? Something like: <code>:%s/"domains": \[\(.* OR \n\)/</code>.</p>
|
||
<p>That will be a post for another time! Let me know on Mastodon if you have any other Neovim search and replace tips and tricks
|
||
that have become invaluable to your workflow. I’m always amazed and impressed with this community and how differently people
|
||
are able to use the same tool.</p>
|
||
<hr>
|
||
<p>By the way, here’s the final output of running the above commands on the sample code above, converted to Python.</p>
|
||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span>mappings <span style="color:#f92672">=</span> {
|
||
</span></span><span style="display:flex;"><span> <span style="color:#e6db74">'uuid'</span>: <span style="color:#e6db74">"1234-1234-1234-1234"</span>,
|
||
</span></span><span style="display:flex;"><span> <span style="color:#e6db74">'domains'</span>: [
|
||
</span></span><span style="display:flex;"><span> <span style="color:#e6db74">'domain_one'</span>,
|
||
</span></span><span style="display:flex;"><span> <span style="color:#e6db74">'domain_two'</span>,
|
||
</span></span><span style="display:flex;"><span> <span style="color:#e6db74">'domain_three'</span>,
|
||
</span></span><span style="display:flex;"><span> <span style="color:#e6db74">'domain_four'</span>,
|
||
</span></span><span style="display:flex;"><span> <span style="color:#e6db74">'domain_five'</span>,
|
||
</span></span><span style="display:flex;"><span> <span style="color:#e6db74">'domain_six'</span>,
|
||
</span></span><span style="display:flex;"><span> ],
|
||
</span></span><span style="display:flex;"><span> <span style="color:#e6db74">'props'</span>: <span style="color:#e6db74">'property-mapping'</span>,
|
||
</span></span><span style="display:flex;"><span>}
|
||
</span></span></code></pre></div><h2 id="resources">Resources<a hidden class="anchor" aria-hidden="true" href="#resources">#</a></h2>
|
||
<p>Here are some various links of resources that I found helpful when learning about the above commands. I’m assuming you’ve
|
||
already read through anything in <a href="https://neovim.io/doc/user/">Neovim’s Helpdocs</a> (<code>:h</code>), but sometimes you need a different take and explanation.</p>
|
||
<ul>
|
||
<li><a href="https://www.reddit.com/r/neovim/comments/i5iptq/vim_search_find_and_replace_a_detailed_guide/">Vim Search, Find & Replace - Reddit</a></li>
|
||
<li><a href="https://vim.fandom.com/wiki/Search_across_multiple_lines">Search Across Multiple Lines - Vim Tips Wiki</a></li>
|
||
<li><a href="https://thevaluable.dev/vim-search-find-replace/">Vim Search and Replace with Examples - The Valuable Dev</a></li>
|
||
<li><a href="https://stackoverflow.com/questions/62751398/how-to-remove-specific-characters-in-vi-or-vim-editor">Removing Specific Characters in Vim - Stack Overflow</a></li>
|
||
</ul>
|
||
|
||
|
||
</div>
|
||
|
||
<footer class="post-footer">
|
||
<ul class="post-tags">
|
||
<li><a href="../tags/snippet.html">Snippet</a></li>
|
||
<li><a href="../tags/neovim.html">Neovim</a></li>
|
||
</ul>
|
||
<nav class="paginav">
|
||
<a class="prev" href="../posts/openresty_and_package_update_issues.html">
|
||
<span class="title">« Prev</span>
|
||
<br>
|
||
<span>QuickHits: OpenResty and Package Updates</span>
|
||
</a>
|
||
<a class="next" href="../posts/mini_neovim.html">
|
||
<span class="title">Next »</span>
|
||
<br>
|
||
<span>Mini Neovim</span>
|
||
</a>
|
||
</nav>
|
||
|
||
|
||
<ul class="share-buttons">
|
||
<li>
|
||
<a target="_blank" rel="noopener noreferrer" aria-label="share Neovim Subtitute Magic on x"
|
||
href="https://x.com/intent/tweet/?text=Neovim%20Subtitute%20Magic&url=%2fposts%2ffind_and_replace_in_neovim.html&hashtags=snippet%2cneovim">
|
||
<svg version="1.1" viewBox="0 0 512 512" xml:space="preserve" height="30px" width="30px" fill="currentColor">
|
||
<path
|
||
d="M512 62.554 L 512 449.446 C 512 483.97 483.97 512 449.446 512 L 62.554 512 C 28.03 512 0 483.97 0 449.446 L 0 62.554 C 0 28.03 28.029 0 62.554 0 L 449.446 0 C 483.971 0 512 28.03 512 62.554 Z M 269.951 190.75 L 182.567 75.216 L 56 75.216 L 207.216 272.95 L 63.9 436.783 L 125.266 436.783 L 235.9 310.383 L 332.567 436.783 L 456 436.783 L 298.367 228.367 L 432.367 75.216 L 371.033 75.216 Z M 127.633 110 L 164.101 110 L 383.481 400.065 L 349.5 400.065 Z" />
|
||
</svg>
|
||
</a>
|
||
</li>
|
||
<li>
|
||
<a target="_blank" rel="noopener noreferrer" aria-label="share Neovim Subtitute Magic on linkedin"
|
||
href="https://www.linkedin.com/shareArticle?mini=true&url=%2fposts%2ffind_and_replace_in_neovim.html&title=Neovim%20Subtitute%20Magic&summary=Neovim%20Subtitute%20Magic&source=%2fposts%2ffind_and_replace_in_neovim.html">
|
||
<svg version="1.1" viewBox="0 0 512 512" xml:space="preserve" height="30px" width="30px" fill="currentColor">
|
||
<path
|
||
d="M449.446,0c34.525,0 62.554,28.03 62.554,62.554l0,386.892c0,34.524 -28.03,62.554 -62.554,62.554l-386.892,0c-34.524,0 -62.554,-28.03 -62.554,-62.554l0,-386.892c0,-34.524 28.029,-62.554 62.554,-62.554l386.892,0Zm-288.985,423.278l0,-225.717l-75.04,0l0,225.717l75.04,0Zm270.539,0l0,-129.439c0,-69.333 -37.018,-101.586 -86.381,-101.586c-39.804,0 -57.634,21.891 -67.617,37.266l0,-31.958l-75.021,0c0.995,21.181 0,225.717 0,225.717l75.02,0l0,-126.056c0,-6.748 0.486,-13.492 2.474,-18.315c5.414,-13.475 17.767,-27.434 38.494,-27.434c27.135,0 38.007,20.707 38.007,51.037l0,120.768l75.024,0Zm-307.552,-334.556c-25.674,0 -42.448,16.879 -42.448,39.002c0,21.658 16.264,39.002 41.455,39.002l0.484,0c26.165,0 42.452,-17.344 42.452,-39.002c-0.485,-22.092 -16.241,-38.954 -41.943,-39.002Z" />
|
||
</svg>
|
||
</a>
|
||
</li>
|
||
<li>
|
||
<a target="_blank" rel="noopener noreferrer" aria-label="share Neovim Subtitute Magic on reddit"
|
||
href="https://reddit.com/submit?url=%2fposts%2ffind_and_replace_in_neovim.html&title=Neovim%20Subtitute%20Magic">
|
||
<svg version="1.1" viewBox="0 0 512 512" xml:space="preserve" height="30px" width="30px" fill="currentColor">
|
||
<path
|
||
d="M449.446,0c34.525,0 62.554,28.03 62.554,62.554l0,386.892c0,34.524 -28.03,62.554 -62.554,62.554l-386.892,0c-34.524,0 -62.554,-28.03 -62.554,-62.554l0,-386.892c0,-34.524 28.029,-62.554 62.554,-62.554l386.892,0Zm-3.446,265.638c0,-22.964 -18.616,-41.58 -41.58,-41.58c-11.211,0 -21.361,4.457 -28.841,11.666c-28.424,-20.508 -67.586,-33.757 -111.204,-35.278l18.941,-89.121l61.884,13.157c0.756,15.734 13.642,28.29 29.56,28.29c16.407,0 29.706,-13.299 29.706,-29.701c0,-16.403 -13.299,-29.702 -29.706,-29.702c-11.666,0 -21.657,6.792 -26.515,16.578l-69.105,-14.69c-1.922,-0.418 -3.939,-0.042 -5.585,1.036c-1.658,1.073 -2.811,2.761 -3.224,4.686l-21.152,99.438c-44.258,1.228 -84.046,14.494 -112.837,35.232c-7.468,-7.164 -17.589,-11.591 -28.757,-11.591c-22.965,0 -41.585,18.616 -41.585,41.58c0,16.896 10.095,31.41 24.568,37.918c-0.639,4.135 -0.99,8.328 -0.99,12.576c0,63.977 74.469,115.836 166.33,115.836c91.861,0 166.334,-51.859 166.334,-115.836c0,-4.218 -0.347,-8.387 -0.977,-12.493c14.564,-6.47 24.735,-21.034 24.735,-38.001Zm-119.474,108.193c-20.27,20.241 -59.115,21.816 -70.534,21.816c-11.428,0 -50.277,-1.575 -70.522,-21.82c-3.007,-3.008 -3.007,-7.882 0,-10.889c3.003,-2.999 7.882,-3.003 10.885,0c12.777,12.781 40.11,17.317 59.637,17.317c19.522,0 46.86,-4.536 59.657,-17.321c3.016,-2.999 7.886,-2.995 10.885,0.008c3.008,3.011 3.003,7.882 -0.008,10.889Zm-5.23,-48.781c-16.373,0 -29.701,-13.324 -29.701,-29.698c0,-16.381 13.328,-29.714 29.701,-29.714c16.378,0 29.706,13.333 29.706,29.714c0,16.374 -13.328,29.698 -29.706,29.698Zm-160.386,-29.702c0,-16.381 13.328,-29.71 29.714,-29.71c16.369,0 29.689,13.329 29.689,29.71c0,16.373 -13.32,29.693 -29.689,29.693c-16.386,0 -29.714,-13.32 -29.714,-29.693Z" />
|
||
</svg>
|
||
</a>
|
||
</li>
|
||
<li>
|
||
<a target="_blank" rel="noopener noreferrer" aria-label="share Neovim Subtitute Magic on facebook"
|
||
href="https://facebook.com/sharer/sharer.php?u=%2fposts%2ffind_and_replace_in_neovim.html">
|
||
<svg version="1.1" viewBox="0 0 512 512" xml:space="preserve" height="30px" width="30px" fill="currentColor">
|
||
<path
|
||
d="M449.446,0c34.525,0 62.554,28.03 62.554,62.554l0,386.892c0,34.524 -28.03,62.554 -62.554,62.554l-106.468,0l0,-192.915l66.6,0l12.672,-82.621l-79.272,0l0,-53.617c0,-22.603 11.073,-44.636 46.58,-44.636l36.042,0l0,-70.34c0,0 -32.71,-5.582 -63.982,-5.582c-65.288,0 -107.96,39.569 -107.96,111.204l0,62.971l-72.573,0l0,82.621l72.573,0l0,192.915l-191.104,0c-34.524,0 -62.554,-28.03 -62.554,-62.554l0,-386.892c0,-34.524 28.029,-62.554 62.554,-62.554l386.892,0Z" />
|
||
</svg>
|
||
</a>
|
||
</li>
|
||
<li>
|
||
<a target="_blank" rel="noopener noreferrer" aria-label="share Neovim Subtitute Magic on whatsapp"
|
||
href="https://api.whatsapp.com/send?text=Neovim%20Subtitute%20Magic%20-%20%2fposts%2ffind_and_replace_in_neovim.html">
|
||
<svg version="1.1" viewBox="0 0 512 512" xml:space="preserve" height="30px" width="30px" fill="currentColor">
|
||
<path
|
||
d="M449.446,0c34.525,0 62.554,28.03 62.554,62.554l0,386.892c0,34.524 -28.03,62.554 -62.554,62.554l-386.892,0c-34.524,0 -62.554,-28.03 -62.554,-62.554l0,-386.892c0,-34.524 28.029,-62.554 62.554,-62.554l386.892,0Zm-58.673,127.703c-33.842,-33.881 -78.847,-52.548 -126.798,-52.568c-98.799,0 -179.21,80.405 -179.249,179.234c-0.013,31.593 8.241,62.428 23.927,89.612l-25.429,92.884l95.021,-24.925c26.181,14.28 55.659,21.807 85.658,21.816l0.074,0c98.789,0 179.206,-80.413 179.247,-179.243c0.018,-47.895 -18.61,-92.93 -52.451,-126.81Zm-126.797,275.782l-0.06,0c-26.734,-0.01 -52.954,-7.193 -75.828,-20.767l-5.441,-3.229l-56.386,14.792l15.05,-54.977l-3.542,-5.637c-14.913,-23.72 -22.791,-51.136 -22.779,-79.287c0.033,-82.142 66.867,-148.971 149.046,-148.971c39.793,0.014 77.199,15.531 105.329,43.692c28.128,28.16 43.609,65.592 43.594,105.4c-0.034,82.149 -66.866,148.983 -148.983,148.984Zm81.721,-111.581c-4.479,-2.242 -26.499,-13.075 -30.604,-14.571c-4.105,-1.495 -7.091,-2.241 -10.077,2.241c-2.986,4.483 -11.569,14.572 -14.182,17.562c-2.612,2.988 -5.225,3.364 -9.703,1.12c-4.479,-2.241 -18.91,-6.97 -36.017,-22.23c-13.314,-11.876 -22.304,-26.542 -24.916,-31.026c-2.612,-4.484 -0.279,-6.908 1.963,-9.14c2.016,-2.007 4.48,-5.232 6.719,-7.847c2.24,-2.615 2.986,-4.484 4.479,-7.472c1.493,-2.99 0.747,-5.604 -0.374,-7.846c-1.119,-2.241 -10.077,-24.288 -13.809,-33.256c-3.635,-8.733 -7.327,-7.55 -10.077,-7.688c-2.609,-0.13 -5.598,-0.158 -8.583,-0.158c-2.986,0 -7.839,1.121 -11.944,5.604c-4.105,4.484 -15.675,15.32 -15.675,37.364c0,22.046 16.048,43.342 18.287,46.332c2.24,2.99 31.582,48.227 76.511,67.627c10.685,4.615 19.028,7.371 25.533,9.434c10.728,3.41 20.492,2.929 28.209,1.775c8.605,-1.285 26.499,-10.833 30.231,-21.295c3.732,-10.464 3.732,-19.431 2.612,-21.298c-1.119,-1.869 -4.105,-2.99 -8.583,-5.232Z" />
|
||
</svg>
|
||
</a>
|
||
</li>
|
||
<li>
|
||
<a target="_blank" rel="noopener noreferrer" aria-label="share Neovim Subtitute Magic on telegram"
|
||
href="https://telegram.me/share/url?text=Neovim%20Subtitute%20Magic&url=%2fposts%2ffind_and_replace_in_neovim.html">
|
||
<svg version="1.1" xml:space="preserve" viewBox="2 2 28 28" height="30px" width="30px" fill="currentColor">
|
||
<path
|
||
d="M26.49,29.86H5.5a3.37,3.37,0,0,1-2.47-1,3.35,3.35,0,0,1-1-2.47V5.48A3.36,3.36,0,0,1,3,3,3.37,3.37,0,0,1,5.5,2h21A3.38,3.38,0,0,1,29,3a3.36,3.36,0,0,1,1,2.46V26.37a3.35,3.35,0,0,1-1,2.47A3.38,3.38,0,0,1,26.49,29.86Zm-5.38-6.71a.79.79,0,0,0,.85-.66L24.73,9.24a.55.55,0,0,0-.18-.46.62.62,0,0,0-.41-.17q-.08,0-16.53,6.11a.59.59,0,0,0-.41.59.57.57,0,0,0,.43.52l4,1.24,1.61,4.83a.62.62,0,0,0,.63.43.56.56,0,0,0,.4-.17L16.54,20l4.09,3A.9.9,0,0,0,21.11,23.15ZM13.8,20.71l-1.21-4q8.72-5.55,8.78-5.55c.15,0,.23,0,.23.16a.18.18,0,0,1,0,.06s-2.51,2.3-7.52,6.8Z" />
|
||
</svg>
|
||
</a>
|
||
</li>
|
||
<li>
|
||
<a target="_blank" rel="noopener noreferrer" aria-label="share Neovim Subtitute Magic on ycombinator"
|
||
href="https://news.ycombinator.com/submitlink?t=Neovim%20Subtitute%20Magic&u=%2fposts%2ffind_and_replace_in_neovim.html">
|
||
<svg version="1.1" xml:space="preserve" width="30px" height="30px" viewBox="0 0 512 512" fill="currentColor"
|
||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape">
|
||
<path
|
||
d="M449.446 0C483.971 0 512 28.03 512 62.554L512 449.446C512 483.97 483.97 512 449.446 512L62.554 512C28.03 512 0 483.97 0 449.446L0 62.554C0 28.03 28.029 0 62.554 0L449.446 0ZM183.8767 87.9921H121.8427L230.6673 292.4508V424.0079H281.3328V292.4508L390.1575 87.9921H328.1233L256 238.2489z" />
|
||
</svg>
|
||
</a>
|
||
</li>
|
||
</ul>
|
||
|
||
</footer>
|
||
</article>
|
||
</main>
|
||
|
||
<footer class="footer">
|
||
<span>© 2024 <a href="../">Norm-working Packets 💾</a></span>
|
||
<span>
|
||
Powered by
|
||
<a href="https://gohugo.io/" rel="noopener noreferrer" target="_blank">Hugo</a> &
|
||
<a href="https://github.com/adityatelange/hugo-PaperMod/" rel="noopener" target="_blank">PaperMod</a>
|
||
</span>
|
||
</footer>
|
||
<a href="#top" aria-label="go to top" title="Go to Top (Alt + G)" class="top-link" id="top-link" accesskey="g">
|
||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 12 6" fill="currentColor">
|
||
<path d="M12 6H0l6-6z" />
|
||
</svg>
|
||
</a>
|
||
|
||
<script>
|
||
let menu = document.getElementById('menu')
|
||
if (menu) {
|
||
menu.scrollLeft = localStorage.getItem("menu-scroll-position");
|
||
menu.onscroll = function () {
|
||
localStorage.setItem("menu-scroll-position", menu.scrollLeft);
|
||
}
|
||
}
|
||
|
||
document.querySelectorAll('a[href^="#"]').forEach(anchor => {
|
||
anchor.addEventListener("click", function (e) {
|
||
e.preventDefault();
|
||
var id = this.getAttribute("href").substr(1);
|
||
if (!window.matchMedia('(prefers-reduced-motion: reduce)').matches) {
|
||
document.querySelector(`[id='${decodeURIComponent(id)}']`).scrollIntoView({
|
||
behavior: "smooth"
|
||
});
|
||
} else {
|
||
document.querySelector(`[id='${decodeURIComponent(id)}']`).scrollIntoView();
|
||
}
|
||
if (id === "top") {
|
||
history.replaceState(null, null, " ");
|
||
} else {
|
||
history.pushState(null, null, `#${id}`);
|
||
}
|
||
});
|
||
});
|
||
|
||
</script>
|
||
<script>
|
||
var mybutton = document.getElementById("top-link");
|
||
window.onscroll = function () {
|
||
if (document.body.scrollTop > 800 || document.documentElement.scrollTop > 800) {
|
||
mybutton.style.visibility = "visible";
|
||
mybutton.style.opacity = "1";
|
||
} else {
|
||
mybutton.style.visibility = "hidden";
|
||
mybutton.style.opacity = "0";
|
||
}
|
||
};
|
||
|
||
</script>
|
||
<script>
|
||
document.getElementById("theme-toggle").addEventListener("click", () => {
|
||
if (document.body.className.includes("dark")) {
|
||
document.body.classList.remove('dark');
|
||
localStorage.setItem("pref-theme", 'light');
|
||
} else {
|
||
document.body.classList.add('dark');
|
||
localStorage.setItem("pref-theme", 'dark');
|
||
}
|
||
})
|
||
|
||
</script>
|
||
<script>
|
||
document.querySelectorAll('pre > code').forEach((codeblock) => {
|
||
const container = codeblock.parentNode.parentNode;
|
||
|
||
const copybutton = document.createElement('button');
|
||
copybutton.classList.add('copy-code');
|
||
copybutton.innerHTML = 'copy';
|
||
|
||
function copyingDone() {
|
||
copybutton.innerHTML = 'copied!';
|
||
setTimeout(() => {
|
||
copybutton.innerHTML = 'copy';
|
||
}, 2000);
|
||
}
|
||
|
||
copybutton.addEventListener('click', (cb) => {
|
||
if ('clipboard' in navigator) {
|
||
navigator.clipboard.writeText(codeblock.textContent);
|
||
copyingDone();
|
||
return;
|
||
}
|
||
|
||
const range = document.createRange();
|
||
range.selectNodeContents(codeblock);
|
||
const selection = window.getSelection();
|
||
selection.removeAllRanges();
|
||
selection.addRange(range);
|
||
try {
|
||
document.execCommand('copy');
|
||
copyingDone();
|
||
} catch (e) { };
|
||
selection.removeRange(range);
|
||
});
|
||
|
||
if (container.classList.contains("highlight")) {
|
||
container.appendChild(copybutton);
|
||
} else if (container.parentNode.firstChild == container) {
|
||
|
||
} else if (codeblock.parentNode.parentNode.parentNode.parentNode.parentNode.nodeName == "TABLE") {
|
||
|
||
codeblock.parentNode.parentNode.parentNode.parentNode.parentNode.appendChild(copybutton);
|
||
} else {
|
||
|
||
codeblock.parentNode.appendChild(copybutton);
|
||
}
|
||
});
|
||
</script>
|
||
</body>
|
||
|
||
</html>
|