Practical Vim< /a> vit Practical Vim< /a> Note that the styling for a Visual selection is the... development I thought I knew Vim, but Practical" name="description"/>
Tải bản đầy đủ - 0 (trang)
Tip 84. Operate on a Complete Search Match

Tip 84. Operate on a Complete Search Match

Tải bản đầy đủ - 0trang

Operate on a Complete Search Match



• 207



Vim’s search command is convenient for jumping between occurrences of a

pattern, but what if we want to make a change to each match?

In some text editors, the search command doesn’t just position the cursor on

a match: it selects the whole thing, which is convenient if we want to operate

on the match. By contrast, in Vim, the entire match is highlighted (as long

as ‘hlsearch’ is enabled), but our cursor is placed at the start of the match. So

if we want to operate on the match, we either have to select the highlighted

text visually or use a motion that covers the same range of text.

Which of Vim’s motions can we use to do that? As always, the answer is “it

depends.” If our pattern matches a complete word, then we could use e or iw

to operate on the word. But what if a match covers only a portion of the word?

What if each match differs in length?

Let’s look at an example. In this excerpt, we’re dealing with classes called

XmlDocument, XhtmlDocument, XmlTag, and XhtmlTag.

search/tag-heirarchy.rb

class XhtmlDocument < XmlDocument; end

class XhtmlTag < XmlTag; end



Suppose that we wanted to rename each class to look like this instead:

class XHTMLDocument < XMLDocument; end

class XHTMLTag < XMLTag; end



We could use the gU{motion} command to convert a range of text to uppercase,

but in this case what would be the ideal motion?

If we had to operate only on the word “Xml,” then we could run gU3l (or 3gUl )

to act on the next three characters. If we had to operate only on the “Document” classes, then we could run gUtD to act on all characters up to, but not

including, the next “D” character. But neither of these solutions works for all

four changes.

Table 24, Operating on a Complete Search Match, on page 208 shows one possible solution.

To begin with, we write a regular expression to match either “Xml” or “Xhtml.”

That’s easy enough: /\vX(ht)?ml\C does the job. The \C item enforces case

sensitivity, so this should work regardless of whether ‘ignorecase’ and/or

‘smartcase’ are enabled. After searching for this pattern, the four ranges of text

that we want to operate on light up with search highlighting, and our cursor

is positioned at the start of the first match.



www.it-ebooks.info



report erratum • discuss



Chapter 13. Search



Keystrokes



Buffer Contents



{start}



class XhtmlDocument < XmlDocument; end

class XhtmlTag < XmlTag; end



/\vX(ht)?ml\C



class XhtmlDocument < XmlDocument; end

class XhtmlTag < XmlTag; end



gU //e



class XHTMLDocument < XmlDocument; end

class XhtmlTag < XmlTag; end



//



class XHTMLDocument < XmlDocument; end

class XhtmlTag < XmlTag; end



.



class XHTMLDocument < XMLDocument; end

class XhtmlTag < XmlTag; end



// .



class XHTMLDocument < XMLDocument; end

class XHTMLTag < XmlTag; end



• 208



Table 24—Operating on a Complete Search Match

Here’s the trick: gU //e . We’re using //e as a motion, which reaches from

the start to the end of the search match. It doesn’t matter whether the match

is three characters long (“Xml”) or five (“Xhtml”); the //e motion will act

on the entire search match.

But now we have a problem. If we press the n key, we’ll repeat the last search,

including the //e offset. Instead of jumping to the start of the next match,

the n key will take us to the end. To get to the start, we’ll have to repeat the

search without the offset by running // .

That’s a bit of a pain, right? The good news is that the dot command will

repeat our last change, namely gU //e . The bad news is that we’ll have to

use // to jump to the start of the following match. The ideal Dot Formula

here would be n. , but we’ll have to settle for // . instead. A Text Object for

Search Matches, on page 209, discusses a more optimal solution, which requires

a plugin.

You may have noticed that this example has an alternative solution: gUfl .

The fl motion would jump from the start of the match to the next occurrence

of the letter l, and since “Xml” and “Xhtml” both end with the same letter, it

would work in both cases.

I didn’t notice this solution when I devised the example, and I think that’s

significant. Uppercase letters have more presence than their lowercase

counterparts, which makes them easier targets to see and therefore to hit

(refer to Think Like a Scrabble® Player, on page 117). When dealing with the

word “MixedCase,” aiming for the next capital letter ( tC ) is easier than the

last lowercase letter before it ( fd ).



www.it-ebooks.info



report erratum • discuss



Create Complex Patterns by Iterating upon Search History



• 209



A Text Object for Search Matches

The ideal Dot Formula requires a single keystroke to move and a single keystroke to

execute the change. The example in Tip 84, on page 206, used three keystrokes just

to move (// ), which falls short of the ideal. It’s surprising that Vim doesn’t have a

more convenient built-in motion for operating on search matches.

With the judicious use of Vim script, we can add this functionality to Vim. My favorite

solution is the textobj-lastpat plugin, by Kana Natsuno,a which adds an i/ text object

for operating on search matches. Using this, we can make the same change as before

just by running gUi/ . Instead of needing three keystrokes (// ) to jump to the next

match, we can get there in just one: n . In other words, we can achieve an ideal Dot

Formula.



a.



http://github.com/kana/vim-textobj-lastpat



Tip 85



Create Complex Patterns by Iterating upon Search History

Writing regular expressions is hard. We won’t get it right the first time, so the

next best thing is to develop a frictionless workflow that allows us to develop

a pattern by iteration. Being able to recall and edit previous items from our

search history is the trick.

In this example text, the prime symbol has been used as a quote mark:

search/quoted-strings.txt

This string contains a 'quoted' word.

This string contains 'two' quoted 'words.'

This 'string doesn't make things easy.'



We want to compose a regular expression to match each quoted string. This

will take a few tries, but when we get it right, we’ll run a substitute command

to transform the text to use real double-quote symbols, like this:

This string contains a “quoted” word.

This string contains “two” quoted “words.”

This “string doesn't make things easy.”



1: A Broad Match

Let’s begin with a crude search:







/\v'.+'



www.it-ebooks.info



report erratum • discuss



Chapter 13. Search



• 210



This matches a single ' character, followed by any character one or more

times, and terminates with a final ' character. After executing this search

command, our document looks like this:

This string contains a 'quoted' word.

This string contains 'two' quoted 'words.'

This 'string doesn't make things easy.'



The first line looks fine, but there’s a problem with line two. The .+ item in

the pattern performs a greedy match, meaning that it matches as many

characters as possible. But we want to generate two separate matches on

this line: one for each quoted word. Let’s go back to the drawing board.



2: Refinement

Instead of using the . symbol to match any character, let’s be a bit more

specific. We actually want to match any character except', which can be done

using [^']+. We’ll refine our pattern to look like this instead:







/\v'[^']+'



We don’t have to type this out from scratch. Instead, we can press / ,

which prepopulates the search field with the most recent pattern. We only

have to make a small change, so we’ll use the and backspace keys to

delete the . character from the pattern and then type in the replacement.

When we execute the search, we’ll get the following matches:

This string contains a 'quoted' word.

This string contains 'two' quoted 'words.'

This 'string doesn't make things easy.'



That’s an improvement. The first two lines match up just as we want them

to, but line three raises a new issue. The ' character is used here as an

apostrophe, which shouldn’t terminate the match. We’ll have to refine our

pattern some more.



3: Another Iteration

Now we need to consider what differentiates an apostrophe from a closing

quote mark. Here are a few examples: “won’t,” “don’t,” and “we’re.” In each

case, the ' character is followed immediately by a letter—not by a space or

punctuation mark. We could update our pattern to allow ' characters as long

as they are followed by a word character. Here’s our next refinement:







/\v'([^']|'\w)+'



www.it-ebooks.info



report erratum • discuss



Tài liệu bạn tìm kiếm đã sẵn sàng tải về

Tip 84. Operate on a Complete Search Match

Tải bản đầy đủ ngay(0 tr)

×