Nhiều con trỏ ở vị trí mong muốn


13

Tôi đang sử dụng plugin vim-multi-cursors .

Tôi muốn đặt con trỏ chính xác nơi tôi muốn. Ví dụ: ( [x]là các vị trí con trỏ):

Lorem ipsum dolor sit amet[1], consectetur adipiscing elit, 
sed do eiusmod tempor incididunt ut labore et dolore magna[2]
aliqua.

Trong Sublime Text, tôi thường đặt con trỏ đầu tiên, sau đó chuyển đến vị trí tiếp theo với các phím mũi tên và đặt con trỏ thứ hai.

Có một cái gì đó tương tự trong VIM? Với plugin này hay plugin khác.

BIÊN TẬP

Sau một bình luận, mối quan tâm của tôi về việc đó đã xuất hiện khi cố gắng viết
\section[My first section in this book]{My first section in this book}
vào một .textập tin. Phản ứng đầu tiên của tôi là viết \section[]{}và sau đó đặt hai con trỏ để viết cùng một thứ bên trong []{}.

Ví dụ khác là thêm _someStuffsau một vài tên biến khác nhau. Ví dụ: bật cái này:

variable1 = 2
my_variable2 = 12
var3 = 14

vào đây:

variable1_someStuff = 2
my_variable2_someStuff = 12
var3_someStuff = 14

Với nhiều con trỏ tôi có thể làm bằng cách chọn một con trỏ cột và sau đó đi đến cuối từ, sau đó chèn, v.v. Nhưng tôi đoán tôi sẽ dễ dàng chọn chính xác nơi tôi muốn con trỏ ở đó.



1
Tôi nghĩ rằng một câu hỏi quan trọng để hỏi là tại sao bạn muốn làm điều đó? Bạn đang cố làm gì vậy? Sử dụng nhiều con trỏ không thực sự "theo cách của Vim", có lẽ có một cách khác để làm những gì bạn muốn, ít nhất là hiệu quả, sử dụng các tính năng tích hợp.
statox

@statox. Xem chỉnh sửa. Tôi đã đưa ra hai ví dụ mà tôi nghĩ đến. Cái thứ hai tôi có thể thực hiện với plugin vim-multi-cursors, nhưng cái đầu tiên tôi không thể, ít nhất là một cách dễ dàng.
tomasyany

@ Nobe4. Cảm ơn, kịch bản thứ hai đã làm nó.
tomasyany

Câu trả lời:


29

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 ivà gõ My first section in this bookvà 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?

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 $avà 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ừ variable1và 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@qvà 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 @qsẽ tự gọi macro thay vì sử dụng 2@q; bạn vừa mới sử dụng @qvà 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 icủa imagesvà 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à 2jchọ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 echocâ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à gdeletenhư 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 normallệ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?"

globalcó một lệnh ngược được vglobalviết tắt v, hoạt động chính xác như globalngoạ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 deletelệ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.


Câu trả lời rất đầy đủ. Tôi thực sự đã biết tất cả các lệnh đó, nhưng chưa bao giờ nghĩ đến việc sử dụng chúng như thế ... Tôi đoán tôi cần thực hành nhiều hơn. Tuy nhiên, tôi phải nói rằng đôi khi 'vim-way' mất nhiều thời gian hơn là chỉ sử dụng một số plugin (ví dụ: ví dụ CSS của bạn có thể được thực hiện nhanh hơn nhiều với plugin tôi đã đề cập) và đôi khi mất nhiều thời gian hơn (thực sự là rất nhiều phần lớn thời gian vim nhanh hơn bất kỳ trình soạn thảo văn bản nào, nếu được sử dụng đúng cách).
tomasyany

Btw, tôi nghĩ rằng câu trả lời của bạn đã khá đầy đủ. Tôi sẽ chấp nhận nó, nhưng nếu bạn muốn thêm chi tiết, xin vui lòng làm và tôi sẽ rất vui khi đọc chúng.
tomasyany

1
@tomasyany: Thật vậy, đôi khi sử dụng "vim way" có vẻ lâu hơn (tôi không thể đếm được bao nhiêu lần tôi dành nhiều thời gian hơn để tạo macro hoạt động so với khi tôi thực hiện các thay đổi theo cách thủ công) nhưng với thực tế, nó sẽ nhanh hơn. Tôi đã sử dụng Vim chỉ một năm và tôi (rất) không phải là một chuyên gia nhưng tôi có thể cảm thấy rằng chỉnh sửa của tôi liên tục cải thiện khi tôi thực hành.
statox

1
Có lẽ nên đề cập đến các gnđối tượng văn bản là tốt. Nó giải quyết một số trường hợp sử dụng của nhiều con trỏ. Tìm kiếm với /, sau đó dgnhoặc cgn, sau đó lặp lại với ..
Justin M. Keyes

@Justin Tôi không thực sự quen thuộc, gntôi sẽ dùng thử và thêm nó sau. Cảm ơn cho đầu lên!
statox

5

Các trường hợp sử dụng đã cho của bạn đối với tôi nghe có vẻ muốn biết .lệnh khóa (lặp lại lệnh Chỉnh sửa cuối cùng)

  • Đi đến nơi đầu tiên, nhấn i, chèn văn bản của bạn,<ESC>
  • di chuyển đến vị trí 2, nhấn .(Dot) ==> Văn bản giống hệt được chèn
  • Để di chuyển xuống một dòng ở đây và chèn lại (khi chèn vào các dòng liên tiếp), nhấn <ALT>-j.

Ví dụ tex của bạn cho tôi được giải quyết bằng:

I\section[]{}<ESC>hhiMy first Sec...<ESC>lll.


Đó là một giải pháp khá hay. Tôi biết hoàn hảo .lệnh chính, nhưng chưa bao giờ nghĩ đến việc sử dụng nó theo cách đó. Tôi đồng ý nó là một cách tốt đẹp. Nhưng câu trả lời của bạn không thực sự đề cập đến câu hỏi thực sự, vì vậy tôi sẽ không thích hợp để chấp nhận nó.
tomasyany

1
Chà, câu hỏi của bạn (sau khi bạn thêm các trường hợp sử dụng mong muốn) nhắc nhở tôi rằng "Tôi thực sự thích chiếc kéo của mình và muốn thắt chặt một ốc vít với chúng. Hãy cho tôi biết làm thế nào". Và tôi chỉ cho bạn một cách sử dụng tiện lợi cho tuốc nơ vít;) (Tôi đã thêm vào như một câu trả lời, vì tôi không biết, làm thế nào để định dạng trong các bình luận)
Alex Stragies

4

Nhiều cách Vim hơn.

Nhiệm vụ đầu tiên:

\section[foobar baz]{foobar baz}

Quy trình làm việc:

\section[]{}
hh
ifoobar baz<Esc>
$.

Nhiệm vụ thứ hai:

variable1 = 2
my_variable2 = 12
var3 = 14

Chỉ huy:

3:norm ea_somestuff

Kết quả:

variable1_somestuff = 2
my_variable2_somestuff = 12
var3_somestuff = 14
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.