Rapid Refactoring With Vim

栏目: IT技术 · 发布时间: 5年前

内容简介:Last weekend, I was tasked with refactoring the 96 unit tests onHere's a small sample of what had to be done (note the lines prefixed with the arrow):had to be converted to:

Last weekend, I was tasked with refactoring the 96 unit tests on ruma-events to use strictly typed json objects using serde_json::json! instead of raw strings. It was rather painless thanks to vim :)

Here's a small sample of what had to be done (note the lines prefixed with the arrow):

→ use serde_json::{from_str};
  
  #[test]
  fn deserialize() {
    assert_eq!(
→       from_str::<Action>(r#"{"set_tweak": "highlight"}"#),
        Action::SetTweak(Tweak::Highlight { value: true })
        );
  }

had to be converted to:

→ use serde_json::{from_value};
  
  #[test]
  fn deserialize() {
    assert_eq!(
→       from_value::<Action>(json!({"set_tweak": "highlight"})),
        Action::SetTweak(Tweak::Highlight { value: true })
        );
  }

The arglist

For the initial pass, I decided to handle imports, this was a simple find and replace operation, done to all the files containing tests. Luckily, modules (and therefore files) containing tests in Rust are annotated with the #[cfg(test)] attribute. I opened all such files:

# `grep -l pattern files` lists all the files
#  matching the pattern

vim $(grep -l 'cfg\(test\)' ./**/*.rs)

# expands to something like:
vim push_rules.rs room/member.rs key/verification/lib.rs

Starting vim with more than one file at the shell prompt populates the arglist. Hit :args to see the list of files currently ready to edit. The square [brackets] indicate the current file. Navigate through the arglist with :next and :prev . I use tpope's vim-unimpaired, which adds ]a and [a , mapped to :next and :prev .

All that's left to do is the find and replace, for which we will be using vim's argdo , applying a substitution to every file in the arglist:

:argdo s/from_str/from_value/g

The quickfix list

Next up, replacing r#" ... "# with json!( ... ) . I couldn't search and replace that trivially, so I went with a macro callinstead, starting with the cursor on ‘r’, represented by the caret, in my attempt to breakdown the process:

BUFFER:    r#" ... "#;
           ^

ACTION:    vllsjson!(

BUFFER     json!( ... "#;
                ^

ACTION:    <esc>$F#

BUFFER:    json!( ... "#;
                       ^

ACTION:    vhs)<esc>

BUFFER:    json!( ... );

Here's the recordedmacro in all its glory: vllsjson!(<esc>$F#vhs)<esc> .

Great! So now we just go ahead, find every occurrence of r# and apply the macro right? Unfortunately, there were more than a few occurrences of raw strings that had to stay raw strings. Enter, the quickfix list.

The idea behind the quickfix list is to jump from one position in a file to another (maybe in a different file), much like how the arglist lets you jump from one file to another.

One of the easiest ways to populate this list with a bunch of positions is to use vimgrep :

# basic usage
:vimgrep pattern files

# search for raw strings
:vimgrep 'r#' ./**/*.rs

Like :next and :prev , you can navigate the quickfix list with :cnext and :cprev . Every time you move up or down the list, vim indicates your index:

(1 of 131): r#"{"set_tweak": "highlight"}"#;

And just like argdo , you can cdo to apply commands to every match in the quickfix list:

:cdo norm! @q

But, I had to manually pick out matches, and it involved some button mashing.

External Filtering

Some code reviews later, I was asked to format all the json inside the json! macro. All you have to do is pass a visual selection through a pretty json printer. Select the range to be formatted in visual mode, and hit : , you will notice the command line displaying what seems to be gibberish:

:'<,'>

'< and '> are marks . More specifically, they are marks that vim sets automatically every time you make a visual selection, denoting the start and end of the selection.

A range is one or more line specifiers separated by a , :

:1,7       lines 1 through 7
:32        just line 32
:.         the current line
:.,$       the current line to the last line
:'a,'b     mark 'a' to mark 'b'

Most : commands can be prefixed by ranges. :help usr_10.txt for more on that.

Alright, lets pass json through python -m json.tool , a json formatter that accepts stdin (note the use of ! to make use of an external program):

:'<,'>!python -m json.tool

Unfortunately that didn't quite work for me because the range included some non-json text as well, a mix of regex and macros helped fix that. I think you get the drift.

Another fun filter I use from time to time is :!sort , to sort css attributes, or :!uniq to remove repeated imports.


以上所述就是小编给大家介绍的《Rapid Refactoring With Vim》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Developer's Guide to Social Programming

Developer's Guide to Social Programming

Mark D. Hawker / Addison-Wesley Professional / 2010-8-25 / USD 39.99

In The Developer's Guide to Social Programming, Mark Hawker shows developers how to build applications that integrate with the major social networking sites. Unlike competitive books that focus on a s......一起来看看 《Developer's Guide to Social Programming》 这本书的介绍吧!

随机密码生成器
随机密码生成器

多种字符组合密码

Base64 编码/解码
Base64 编码/解码

Base64 编码/解码

URL 编码/解码
URL 编码/解码

URL 编码/解码