Sử dụng nhiều con trỏ không phải là một thứ Vimmer
Như tôi đã nói trong các nhận xét sử dụng nhiều con trỏ (ngay cả với một plugin) không thực sự "theo cách của Vim", tôi hoàn toàn hiểu rằng nó rất hấp dẫn đối với ai đó đến từ Sublime-Text nhưng bạn thường có thể tìm thấy các lựa chọn thay thế ít nhất là hiệu quả với các tính năng tích hợp Vim.
Tất nhiên, việc tìm kiếm các giải pháp thay thế này không phải lúc nào cũng dễ dàng và đôi khi mất nhiều thời gian nhưng sẽ dễ dàng hơn với trải nghiệm Vim của bạn và bạn sẽ thấy rằng với thời gian, nhiều con trỏ sẽ dường như vô dụng với bạn.
Điều đó thật tuyệt nhưng làm thế nào tôi có thể tìm thấy một cách khác?
Không có câu trả lời chung vì nó phụ thuộc rất nhiều vào những gì bạn đang cố gắng làm, tôi sẽ chỉ cố gắng đưa ra một số gợi ý về những điều đầu tiên để thử:
Lệnh chấm .
Lệnh Dot có lẽ là một trong những công cụ mạnh nhất trong Vim, nó chỉ đơn giản cho phép chúng ta lặp lại thay đổi cuối cùng. Tôi không thể giải thích điều đó tốt hơn Drew Neil trong Vim thực tế của mình . Tôi nghĩ rằng mỗi Vimmer nên xem xét việc đọc cuốn sách này.
Điểm mạnh của lệnh này là thay đổi cuối cùng có thể là một hành động làm việc trên một ký tự, một dòng hoặc toàn bộ tệp. Ví dụ: một thay đổi có thể được phân định bởi thời điểm bạn vào chế độ chèn và thời điểm bạn quay lại chế độ bình thường.
Với ý nghĩ đó, thật dễ dàng để làm những gì bạn muốn làm với đa tiền:
Trước tiên hãy thiết lập môi trường của chúng tôi: Hãy viết như bạn đề xuất
\section[]{}
Sau đó thực hiện thay đổi lặp lại
Con trỏ hiện đang bật }
, nhấn F[
để quay lại [
ký tự. Sau đó nhập chế độ chèn với i
và gõ My first section in this book
và quay lại chế độ bình thường với ESC
:
\section[My first section in this book]{}
Và đây là phần ma thuật: Hãy gõ f{
con trỏ vào {
nhân vật và nhấn .
để lặp lại thay đổi cuối cùng:
\section[My first section in this book]{My first section in this book}
Tất cả thách thức của lệnh dot là tìm hiểu cách thực hiện các thay đổi có thể lặp lại: nó sẽ đi kèm với việc mò mẫm Vim nhưng điều cơ bản là hiểu cách thực hiện thay đổi của bạn theo cách lặp lại.
Ví dụ: để chèn dấu chấm phẩy ở cuối dòng bạn sẽ thích sử dụng
A;
thay vì $a;
. Tại sao?
Vì A;
tạo ra một hành động nguyên tử nên khi bạn sử dụng .
trên một dòng khác, bất kể bạn ở đâu trong dòng đó, bạn sẽ chèn dấu chấm phẩy ở cuối. Trong khi đó, khi sử dụng, $a;
bạn chia sự thay đổi của mình thành hai phần $a
và phần chèn ;
vì vậy nếu bạn sử dụng .
nó sẽ chèn dấu chấm phẩy vào vị trí hiện tại của con trỏ.
CHÚ THÍCH Công thức ma thuật trong Vim là n.
. Một quy trình làm việc thực sự tuyệt vời là:
- tìm kiếm địa điểm bạn muốn chỉnh sửa
/pattern
- thực hiện chỉnh sửa lặp lại của bạn
- sử dụng
n
để đi đến nơi tiếp theo để chỉnh sửa
- sử dụng
.
để lặp lại chỉnh sửa
- lặp lại hai bước cuối cùng: Bạn là vua của thế giới (hoặc ít nhất là chỉnh sửa)
macro
Macro là một công cụ cực kỳ quan trọng khác trong Vim vì nó cho phép bạn ghi lại một chuỗi các lần nhấn phím và lặp lại nó như thể bạn gõ lại nó.
Tôi sẽ sử dụng, ví dụ, trường hợp sử dụng thứ hai của bạn:
variable1 = 2
my_variable2 = 12
var3 = 14
Một lần nữa, điều quan trọng là tìm hiểu cách làm cho macro của bạn hiệu quả (Tôi sẽ đưa ra một ví dụ phản hồi ngay sau đó):
Đặt con trỏ của bạn vào từ variable1
và bắt đầu ghi lại macro của bạn
qq
. Điều này có nghĩa là "bắt đầu ghi lại tất cả các tổ hợp phím trong tương lai của tôi trong sổ đăng ký có tên q
".
Bắt đầu gõ chỉnh sửa của bạn:
0
đi ở đầu dòng
e
đi đến cuối từ đầu tiên
a
để nối sau con trỏ của bạn
.someStuff
để thêm văn bản mong muốn
<Esc>
ngừng chèn
j
đi trên dòng tiếp theo
q
dừng ghi macro
Bạn sẽ nhận được:
variable1.someStuff = 2
my_variable2 = 12
var3 = 14
- Bây giờ bạn có thể sử dụng macro để lặp lại chỉnh sửa của bạn. Khi bạn đang ở đúng dòng để chỉnh sửa, bạn chỉ cần thực hiện macro với
@q
. Vì chúng tôi muốn thực hiện hai lần bạn có thể sử dụng 2@q
và bạn sẽ nhận được kết quả sau:
variable1.someStuff = 2
my_variable2.someStuff = 12
var3.someStuff = 14
CHÚ THÍCH 1 Như bạn có thể nhận thấy, sử dụng 0ea
ở đầu macro là thực sự quan trọng. Thật vậy, nếu bạn đã đặt con trỏ ở cuối từ đầu tiên trước khi ghi macro và thực hiện lại thì kết quả của bạn sẽ là:
variable1.someStuff = 2
my_variable2 = 12.someStuff
var3 = 14.someStuff
Khi con trỏ của bạn, văn bản sẽ được chèn vào vị trí của con trỏ sau khi thay đổi dòng (nghĩa là cuối dòng trong trường hợp này)
CHÚ THÍCH 2 Macro cực kỳ mạnh mẽ và bạn thậm chí có thể tạo các macro đệ quy khi bạn cảm thấy thoải mái với chúng. Ở đây macro của bạn có thể có:
`0ea.someStuff<Esc>j@q`
Trận chung kết @q
sẽ tự gọi macro thay vì sử dụng 2@q
; bạn vừa mới sử dụng @q
và tất cả công việc sẽ được thực hiện.
khối thị giác
Ở đây có một mẹo khác không áp dụng trực tiếp cho trường hợp sử dụng của bạn nhưng có thể thực sự hữu ích để chỉnh sửa một số lượng lớn dòng cùng một lúc. Hãy lấy đoạn trích mã CSS này:
li.one a{ background-image: url('/images/sprite.png'); }
li.two a{ background-image: url('/images/sprite.png'); }
li.three a{ background-image: url('/images/sprite.png'); }
Điều gì nếu bạn di chuyển các sprite từ images
đến components
?
Vâng, bạn có thể đặt con trỏ của bạn trên i
của images
và nhấn <C-v>
. Điều này sẽ bắt đầu chế độ khối trực quan cho phép chọn các khối. Bây giờ bạn có thể nhập t/
để chọn từ bạn muốn thay đổi và 2j
chọn tất cả các lần xuất hiện của từ đó.
Sau đó, bạn chỉ cần gõ c
để thay đổi từ và sau đó components
. Khi bạn thoát khỏi chế độ chèn, bạn sẽ thấy:
li.one a{ background-image: url('/components/sprite.png'); }
li.two a{ background-image: url('/components/sprite.png'); }
li.three a{ background-image: url('/components/sprite.png'); }
Bộ chỉ huy toàn cầu
Lệnh toàn cầu là một công cụ cho phép áp dụng lệnh chế độ ex trên các dòng khớp với một mẫu, một lần nữa, đó là cách tốt để áp dụng cùng một thay đổi trên các vị trí khác nhau mà không cần nhiều con trỏ.
Cú pháp như sau:
:[range] g / pattern / command
Để biết thêm chi tiết về [range]
tham số xin vui lòng xem :h :range
. Tôi sẽ không nêu chi tiết ở đây, tôi chỉ đơn giản nhắc nhở %
đại diện cho toàn bộ tệp, '<,'>
đại diện cho lựa chọn cuối cùng và 1,5
đại diện cho các dòng từ 1 đến 5 của tệp.
Tham số này xác định các dòng sẽ được xử lý bằng lệnh toàn cầu. Nếu không có phạm vi nào được chỉ định, thì lệnh toàn cục sẽ sử dụng %
theo mặc định.
Đối số [mẫu] là mẫu tìm kiếm mà bạn đã quen sử dụng với công cụ tìm kiếm. Vì nó tích hợp lịch sử tìm kiếm, bạn có thể để trống trường này và lệnh toàn cầu sau đó sẽ sử dụng mẫu tìm kiếm cuối cùng trong lịch sử tìm kiếm.
Cuối cùng, tham số [lệnh] là một lệnh ex như bạn có thể đã quen.
Bây giờ hành vi của lệnh toàn cầu là khá đơn giản:
- Lặp lại qua tất cả các dòng được xác định trong tham số [phạm vi]
- Nếu dòng hiện tại khớp với mẫu đã xác định, áp dụng lệnh
Vì tham số [lệnh] là một lệnh ex, bạn có thể làm rất nhiều thứ. Hãy lấy mã giả sau đây không thú vị và có nhiều thông báo gỡ lỗi:
var myList = null
var i = 0
myList = new List()
echo "List instantiated"
for (i=0; i<10; i++)
myList.Add(i)
echo i . " added to the list"
echo "end of for loop"
Bây giờ hãy nói rằng bạn chắc chắn mã này hoạt động và bạn muốn xóa các echo
câu lệnh vô dụng này:
Bạn có thể áp dụng lệnh toàn cầu của mình trên toàn bộ tệp để bạn phải trả trước lệnh bằng %
(hoặc không có gì vì đó %
là phạm vi mặc định).
Bạn biết rằng các dòng bạn muốn xóa tất cả khớp với mẫu echo
Bạn muốn xóa những dòng này để bạn sẽ phải sử dụng lệnh :delete
cũng có thể được viết tắt làd
Vì vậy, bạn sẽ chỉ cần sử dụng chức năng sau đây:
:%global/echo/delete
Mà cũng có thể được viết tắt là
:g/echo/d
Lưu ý rằng đã %
biến mất, global
được viết tắt là g
và delete
như d
. Như bạn có thể tưởng tượng kết quả là:
var myList = null
var i = 0
myList = new List()
for (i=0; i<10; i++)
myList.Add(i)
CHÚ THÍCH 1 Một điểm quan trọng khiến tôi mất một thời gian để nhận ra rằng
normal
lệnh là một lệnh ex có nghĩa là bạn có thể sử dụng nó với lệnh toàn cầu. Điều đó có thể thực sự mạnh mẽ: giả sử rằng tôi muốn sao chép tất cả các dòng có tiếng vang, tôi không cần macro hay thậm chí là công thức ma thuật n.
. Tôi chỉ có thể sử dụng
:g/echo/normal YP
Và Voila:
var myList = null
var i = 0
myList = new List()
echo "List instantiated"
echo "List instantiated"
for (i=0; i<10; i++)
myList.Add(i)
echo i . " added to the list"
echo i . " added to the list"
echo "end of for loop"
echo "end of for loop"
CHÚ THÍCH 2 "Này, nếu tôi muốn sử dụng lệnh của mình trên các dòng không khớp với một mẫu cụ thể thì sao?"
global
có một lệnh ngược được vglobal
viết tắt v
, hoạt động chính xác như global
ngoại trừ lệnh sẽ được áp dụng trên các dòng không khớp với tham số [mẫu]. Cách này nếu chúng ta áp dụng
:v/echo/d
Trên ví dụ trước, chúng tôi nhận được:
echo "List instantiated"
echo i . " added to the list"
echo "end of for loop"
Các delete
lệnh đã được áp dụng trên dây chuyền mà không chứa echo
.
Ở đây tôi hy vọng rằng một vài gợi ý sẽ cung cấp cho bạn ý tưởng về cách thoát khỏi plugin đa con trỏ của bạn và sử dụng Vim theo cách Vim ;-)
Như bạn có thể tưởng tượng những ví dụ này khá đơn giản và chỉ được thực hiện để chứng minh rằng khi bạn làm theo cách Vim, bạn thực sự hiếm khi cần một vài con trỏ. Lời khuyên của tôi sẽ là khi bạn gặp phải một tình huống mà bạn nghĩ nó sẽ hữu ích, hãy viết nó ra và dành một chút thời gian sau đó để tìm ra giải pháp tốt hơn. 99% thời gian cuối cùng bạn sẽ tìm thấy một cách nhanh hơn / hiệu quả hơn để làm điều đó.
Ngoài ra tôi sẽ lặp lại một lần nữa nhưng tôi thực sự khuyến khích bạn đọc
Vim thực tế của Drew Neil vì cuốn sách này không phải là "Làm thế nào để làm điều đó hay điều này trong Vim" mà là về "Cách học cách suy nghĩ theo cách Vim" sẽ cho phép bạn xây dựng giải pháp của riêng mình cho các vấn đề trong tương lai theo cách tốt.
PS Đặc biệt cảm ơn @Alex Stragies cho công việc chỉnh sửa của anh ấy và những chỉnh sửa anh ấy đã thực hiện cho bài viết dài này.