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 100. Alphabetize the Properties of Each Rule in a CSS File

Tip 100. Alphabetize the Properties of Each Rule in a CSS File

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

Alphabetize the Properties of Each Rule in a CSS File


Buffer Contents


html {

margin: 0;

padding: 0;

border: 0;

font-size: 100%;

font: inherit;

vertical-align: baseline;



html {

margin: 0;

padding: 0;

border: 0;

font-size: 100%;

font: inherit;

vertical-align: baseline;



html {

border: 0;

font-size: 100%;

font: inherit;

margin: 0;

padding: 0;

vertical-align: baseline;


• 243

Table 27—Sort a Subset of a File

suppose that we had a style sheet containing hundreds of rules. Wouldn’t it

be better if we could automate the process somehow?

Sort Properties for Every Block of Rules

We can sort the properties for every block of rules in the file with a single

:global command. Say we run this command on our style sheet:

:g/{/ .+1,/}/-1 sort

We should end up with this result:

html {

border: 0;

font-size: 100%;

font: inherit;

margin: 0;

padding: 0;

vertical-align: baseline;


report erratum • discuss

Chapter 15. Global Commands

• 244

body {

background: white;

color: black;

line-height: 1.5;


The sort command has been executed inside the {} block for each rule. Our

sample style sheet only contains a dozen lines, but this technique would work

just as well for a longer CSS file.

This command is complex, but understanding how it works will help us to

appreciate just how powerful the :global command can be. The standard form

looks like this:


Remember: Ex commands can usually accept a range themselves (as discussed

in Tip 28, on page 54). This is still true for the [cmd] in the context of a :global

command. So we could expand the template as follows:


The [range] for our [cmd] can be set dynamically using the match from :g/{pattern}

as a reference point. Normally the . address stands for the line that the cursor

is positioned on. But in the context of a :global command, it stands for each

line in turn that matches the specified {pattern}.

We can break our command into two separate Ex commands. Let’s work our

way backward from the end. This is a valid Ex command:

:.+1,/}/-1 sort

If we strip out the offsets from our range, it becomes simply .,/}/. We can

interpret this as “from the current line up until the next line that matches

the /}/ pattern.” The +1 and -1 offsets simply narrow the range to focus on the

contents of the {} block. If we place our cursor on either line 1 or line 9 of

our original unsorted CSS file, then this Ex command would alphabetize the

rules inside the corresponding {} block.

We just need to position our cursor at the start of each {} block and then run

the :.,/}/sort command to alphabetize the rules inside that block. Got that? Now

try executing a search using the {pattern} from our :global command:


That places our cursor at the top of a {} block, right where we need it. Now

let’s put our :global and [cmd] Ex commands back together:

:g/{/ .+1,/}/-1 sort

report erratum • discuss

Alphabetize the Properties of Each Rule in a CSS File

• 245

The { pattern matches the first line of each {} block. For every line that

matches, the :sort command is executed on a [range] that terminates at the end

of the {} block. The end result is that all CSS properties are alphabetized

within each block of rules.


A generalized form of this :global command goes like this:

:g/{start}/ .,{finish} [cmd]

We can read this as “For each range of lines beginning with {start} and ending

with {finish}, run the specified [cmd].”

We could use the same formula for a :global command in combination with

any Ex command. For example, suppose that we wanted to indent the specified

ranges. We could do so with the :> Ex command (see :h :> ):

:g/{/ .+1,/}/-1 >

6 lines >ed 1 time

3 lines >ed 1 time

Note that the :> command echoes a message each time it is invoked, whereas

:sort doesn’t. We can mute these messages by prefixing our [cmd] with :silent

(see :h :sil ):

:g/{/sil .+1,/}/-1 >

This technique is especially useful in cases where the :g/{pattern} matches a

large number of lines.

report erratum • discuss

Part VI


“Do one thing, and do it well” is a principle of Unix

philosophy. Vim provides wrapper commands that

make it easy to call external programs such as make

or grep. Some tasks require deeper integration with

the text editor, so Vim provides native tools for spell

checking and autocompletion and also provides a

built-in :vimgrep command. In this part of the book

we’ll study Vim’s toolbox and its interface for

working with external tools.


Index and Navigate

Source Code with ctags

ctags is an external program that scans through a codebase and generates an

index of keywords. It was originally built into Vim, but with the release of Vim

version 6, ctags became a separate project. That heritage is evident today in

Vim’s tight integration with ctags.

Vim’s ctags support allows us to navigate around a codebase by quickly

jumping to definitions of functions and classes. We’ll see how in Tip 103, on

page 254. As a secondary benefit, we can also use the output from ctags to

generate a word list for autocompletion, as we’ll see in Tag Files, on page 280.

Tag navigation and tag autocompletion won’t work unless Vim knows where

to look for an up-to-date index file. Tip 102, on page 252, shows how to configure Vim to work with ctags. But first, let’s find out how to install and execute


Tip 101

Meet ctags

To use Vim’s tag navigation features, we must first install ctags. Then we’ll learn

how to execute the program and understand the index that it generates.

Installing Exuberant Ctags

Linux users should be able to get ctags with their package manager. For

example, on Ubuntu you can install it by running the following:

report erratum • discuss

Chapter 16. Index and Navigate Source Code with ctags

• 250

$ sudo apt-get install exuberant-ctags

OS X ships with a BSD program called ctags. Beware: this is not the same

thing as Exuberant Ctags. You’ll have to install Exuberant Ctags yourself.

Using homebrew, it’s as easy as this:

$ brew install ctags

Check that ctags is installed and that it’s in your path by running the following:

$ ctags --help

Exuberant Ctags 5.8, Copyright (C) 1996-2009 Darren Hiebert

Compiled: Dec 18 2010, 22:44:26


If you don’t get this message, you might have to modify your $PATH. Make sure

that /usr/local/bin takes precedence over /usr/bin.

Complements to ctags

Mozilla runs a project called Doctor JS,a which includes a jsctags program. This performs static analysis on JavaScript code, with a deep understanding of the language’s

semantics (jsctags itself is implemented in JavaScript). jsctags produces output in the

same format as ctags, so it works seamlessly with Vim.

There’s nothing proprietary about the tags file format; it’s plain text. Anybody can

write a script to generate tags files that Vim understands.


Indexing a Codebase with ctags

We can invoke ctags from the command line, giving it the path for one or more

files that we would like it to index. The source code distributed with this book

includes a small demo program consisting of three Ruby files. Let’s run ctags

on this codebase:

$ cd code/ctags

$ ls

anglophone.rb francophone.rb speaker.rb

$ ctags *.rb

$ ls

anglophone.rb francophone.rb speaker.rb tags

Note that ctags has created a plain-text file called tags. It contains an index of

the keywords from the three source files that ctags analyzed.

report erratum • discuss

Meet ctags

• 251

The Anatomy of a tags File

Let’s look inside the tags file we just generated. Note that some lines have been

truncated to fit the page:




/extended format/



/0=unsorted, 1=sorted, 2=foldcase/


Darren Hiebert //


Exuberant Ctags //


/official site/






/^class Anglophone < Speaker$/;"



francophone.rb /^class Francophone < Speaker$/;"


Speaker speaker.rb

/^class Speaker$/;"




/^ def initialize(name)$/;"




/^ def speak$/;"




francophone.rb /^ def speak$/;"





/^ def speak$/;"



The tags file begins with a few lines of metadata. After that it lists one keyword

per line, along with the filename and address where that keyword is defined

in the source code. The keywords are arranged in alphabetical order, so Vim

(or any text editor, for that matter) can rapidly locate them with a binary


Keywords Are Addressed by Pattern, Not by Line Number

The specification for the tags file format states that the address could be any

Ex command.1 One option would be to use absolute line numbers. For

example, we could make the cursor jump to an address on line 42 with the

Ex command :42. But think of how brittle that could be. Adding just one new

line at the top of a file would throw every address out of step.

Instead, ctags uses the search command to address each keyword (if you’re

not convinced that search is an Ex command, try entering :/pattern). This

method is more robust than using line numbers, but it’s still not perfect.

What if the search command used to address a particular keyword had more

than one match for a given file?

That situation shouldn’t arise, because the pattern can match as many lines

of code as is necessary to produce a unique address. So long as the line length

doesn’t exceed 512 characters, a tags file will remain backward compatible

with vi. Of course, as a search pattern becomes longer, it, too, becomes brittle

in its own way.


report erratum • discuss

Chapter 16. Index and Navigate Source Code with ctags

• 252

Keywords Are Tagged with Metadata

The classic tags file format only required three tab-separated fields: the keyword, the filename, and the address. But the extended format used today

allows for additional fields at the end to provide metadata about the keyword.

In this example, we can see that the Anglophone, Francophone, and Speaker keywords

are labeled c for class, while initialize and speak are labeled f for function.

Tip 102

Configure Vim to Work with ctags

If we want to use Vim’s ctag navigation commands, we must ensure that the

tags file is up-to-date and that Vim knows where to look for it.

Tell Vim Where to Find the Tags File

The ‘tags’ option specifies where Vim should look to find a tags file (:h 'tags' ).

When ./ is used in the ‘tags’ option, Vim replaces it with the path of the currently active file. We can inspect the defaults:

:set tags?


With these settings, Vim looks for a tags file in the directory of the current file

and in the working directory. Under certain conditions, if a match is found

in the first tags file, Vim won’t even look in the second file (see :h tags-option

for more details). Using Vim’s default settings, we could keep a tags file in

every subdirectory of our project. Or we could keep it simple by creating a

global tags file in the project root directory.

If you run ctags often enough to keep the index up-to-date, then your tags file

(or files) could show up in every source code check-in. To keep your commit

history clean, tell your source control to ignore tags files.

Generate the tags File

As we saw in Indexing a Codebase with ctags, on page 250, ctags can be executed

from the command line. But we needn’t leave Vim to regenerate the tags file.

Simple Case: Execute ctags Manually

We can invoke ctags directly from Vim by running the following:

:!ctags -R

report erratum • discuss

Configure Vim to Work with ctags

• 253

Starting from Vim’s current working directory, this command would recurse

through all subdirectories, indexing every file. The resulting tags file would be

written in the current working directory.

If we were to tweak the command by adding such options as --exclude=.git or

--languages=-sql, typing it out would become more of a chore. We could save

ourselves some time by creating a mapping for it:

:nnoremap :!ctags -R

That lets us rebuild the index just by pressing the key, but we still have

to remember periodically to generate the tags file. Now let’s consider a couple

of options for automating this process.

Automatically Execute ctags Each Time a File is Saved

Vim’s autocommand feature allows us to invoke a command on each occurrence of an event, such as a buffer being created, opened, or written to file.

We could set up an autocommand that invokes ctags every time we save a file:

:autocmd BufWritePost * call system("ctags -R")

This would re-index our entire codebase each time we saved changes to a

single file.

Automatically Execute ctags with Version Control Hooks

Most source control systems provide hooks that allow us to execute a script

in response to events on the repository. We can use these to instruct our

source control to re-index the repository every time we commit our code.

In “Effortless Ctags with Git,” Tim Pope demonstrates how to set up hooks

for the post-commit, post-merge, and post-checkout events.2 The beauty of this solution

is that it uses global hooks, so configuring each individual repository on your

system is unnecessary.


Each strategy for indexing our source code has its pros and cons. The manual

solution is simplest, but having to remember to regenerate the index means

that it’s more likely to go stale.

Using an autocommand to invoke ctags every time a buffer is saved ensures

that our tags file is always up-to-date, but at what cost? For a small codebase,

the time taken to run ctags may be imperceptible, but for larger projects, the


report erratum • discuss

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

Tip 100. Alphabetize the Properties of Each Rule in a CSS File

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