Bearbeiten : Die Antwort von Peter Rincker ist kürzer, leichter zu erklären und kann so oft wiederholt werden, wie Sie möchten. Meine Lösung ist zu lang und kann nicht für mehrere Wörter wiederholt werden. Ich sollte die Antwort löschen, aber vielleicht interessiert sich jemand dafür, also lasse ich es hier.
Ich bin mir nicht sicher, ob Sie dies möchten, aber versuchen Sie den folgenden Code:
function! NextWordWithLetter(type)
normal! `]vy
let letter = @0
let line = getline('.')
let list = split(line)
for word in list
if matchstr(word, '\%1c.') ==# letter
let col = match(line, word) + 1
execute "normal! " . col . "|"
break
endif
endfor
endfunction
nnoremap <silent> <leader>g :set operatorfunc=NextWordWithLetter<cr>g@
Die Zuordnung zum Aufrufen der Funktion lautet <leader>g<motion>
.
Wenn Sie den Cursor auf das nächste Wort bewegen möchten, das mit dem Buchstaben beginnt p
und ,
Ihr Leitschlüssel ist, können Sie Folgendes eingeben ,gfp
.
Tor
Sie möchten zum nächsten Wort gehen, das mit einem bestimmten Buchstaben beginnt. Ich weiß nicht, ob in vim bereits eine solche Bewegung integriert ist, aber nehmen wir an, dass dies nicht der Fall ist.
Wir brauchen eine neue Bewegung definieren (wie w
, b
, e
usw.). Normalerweise verwenden Sie den onoremap
Befehl , um eine neue Bewegung oder ein neues Objekt zu definieren . Es wird hier ausführlich erklärt .
Ich weiß nicht, wie Sie Ihr Ziel auf diese Weise erreichen können, aber ich weiß, wie Sie einen neuen Operator definieren, der indirekt das tut, was Sie wollen.
Ich sage indirekt, weil der Zweck eines neuen Operators normalerweise nicht darin besteht , sich irgendwohin zu bewegen , sondern etwas an einem Textstück zu tun .
Vim erklärt in der Hilfe, wie Sie einen neuen Operator erstellen : :h map-operator
. Es wird auch hier , hier und hier erklärt .
Die Syntax mag Ihnen seltsam erscheinen, aber so scheint es in Vimscript zu funktionieren:
g@
ist ein spezieller Operator ( c
zum Ändern, d
Löschen, y
Kopieren usw.), mit dem Sie Ihren eigenen Operator erstellen können.
Wenn Sie g@{motion}
vim eingeben, suchen Sie nach der opfunc
Option, deren Wert der Name einer Funktion sein soll, setzen Sie die Markierungen `[
und `]
um den Text, den Sie verschoben hätten, wenn Sie gerade getippt hätten {motion}
(dazu später mehr), und führen Sie die Funktion aus, die dies kann Mach alles, was du willst.
Sie können verschiedene Operatoren erstellen, indem Sie verschiedene Funktionen schreiben und die opfunc
Option auf den Namen der Funktion setzen, die Sie verwenden möchten.
Bevor wir uns jedoch mit der Funktionsweise unserer Funktion befassen, werfen wir einen Blick auf das Mapping, das wir zum Auslösen benötigen.
Kartierung
Am Ende des Codes befindet sich diese Zeile:
nnoremap <silent> <leader>g :set operatorfunc=NextWordWithLetter<cr>g@
Es teilt vim mit, dass es bei jedem Treffer <leader>g
lautlos ( <silent>
) den Wert der operatorfunc
Option auf setzen NextWordWithLetter
und dann im normalen Modus drücken muss g@
.
Der Bediener g@
wartet auf eine Bewegung, um die Markierungen `[
und `]
den Text zu setzen, mit dem Sie sich bewegt hätten, {motion}
bevor er die in gespeicherte Funktion ausführt opfunc
. Hier ist die Funktion NextWordWithLetter()
.
Sie können dasselbe tun, indem Sie im Befehlsmodus Folgendes eingeben:
:set operatorfunc=NextWordWithLetter
Dann im normalen Modus: g@
Dann immer im normalen Modus:{motion}
Aber natürlich wäre es mühsam, also erstellen wir das Mapping <leader>g
, das die operatorfunc
Option automatisch auf den gewünschten Funktionsnamen setzt und g@
für uns trifft .
Nehmen wir an, Ihr Führungsschlüssel ist ,
und Sie suchen nach dem nächsten Wort, das mit dem Buchstaben beginnt p
. Mit unserem Mapping können Sie eingeben ,gfp
.
Als Ergebnis vim wird die Markierungen gesetzt `[
und `]
um den Text zwischen dem Cursor und dem nächsten Zeichen p
, Satz opfunc
zu NextWordWithLetter
, und wegen des Wertes dieser Option wird die Funktion ausführen NextWordWithLetter()
.
Schauen wir uns als nächstes an, was die Funktion tut.
Variablen einstellen
Zuerst müssen wir der Funktion mitteilen, nach welchem Zeichen wir suchen:
normal! `]vy
Der normal
Befehl gibt eine beliebige Folge von Zeichen ein, die Sie an ihn übergeben, als wären Sie im normalen Modus. Hier ist die Zeichenfolge `]vy
.
Wenn Sie sich in einem Puffer befinden, können Sie mit dem normalen Befehl überall eine Markierung setzen m{letter}
.
Wenn Sie die Markierung a
an der Stelle platzieren möchten, an der sich Ihr Cursor befindet, geben Sie ein ma
. Dann können Sie sich bewegen und zur gleichen Zeile wie die Markierung a
mit dem Befehl 'a
oder zu dem genauen Zeichen zurückkehren, bei dem Sie die Markierung a
mit dem Befehl setzen `a
.
Sie können alle Ihre Markierungen mit dem Befehl sehen :marks
. Die Großbuchstaben sind global und können verwendet werden, um über Puffer zu springen. Die Kleinbuchstaben sind lokal für einen Puffer.
Es gibt zwei spezielle Zeichen, die vim automatisch für uns setzt: `[
und `]
. Immer wenn Sie Text ändern oder ziehen, setzt vim diese Markierungen darum ( :h '[
).
Kehren wir zu unserem Beispiel zurück: Sie wollten zum nächsten Wort gehen, das mit dem Buchstaben beginnt p
, also haben Sie getroffen ,gfp
. fp
ist ein Befehl, der den Cursor zum nächsten Zeichen bewegt p
.
An diesem Punkt setzt vim automatisch die Markierungen `[
und `]
den Text, um den wir uns bewegt hätten, wenn wir gerade getippt hätten {motion}
( fp
in unserem Beispiel).
Es steht in der Hilfe ( :h g@
):
g @ {motion} Rufen Sie die mit der Option 'operatorfunc' festgelegte Funktion auf. Die Markierung '[befindet sich am Anfang des Textes, der von {motion} verschoben wurde, die Markierung'] am letzten Zeichen des Textes.
Wir haben noch nichts geändert oder gerissen. Warum setzt vim diese Zeichen bereits? Weil es denkt, dass die Funktion etwas am Text tun möchte und die Funktion diese Markierungen benötigt, um den zu bearbeitenden Text zu identifizieren.
Wenn der normal
Befehl eingegeben wird `]vy
, kann er wie folgt gelesen werden:
Gehen Sie zur Markierung `]
(letztes Zeichen des Textes, der verschoben wurde), wechseln Sie in den visuellen Modus ( v
) und kopieren Sie die visuelle Auswahl ( y
) .
Jetzt haben wir Ihren gesuchten Charakter (Charakter p
) kopiert . Alles, was Sie kopieren, befindet sich in einem Register. Es gibt verschiedene Register in vim, von denen jedes für einen anderen Zweck verwendet wird. Um sie anzusehen :reg
, geben Sie ein und wissen Sie, in welchem Register was gespeichert ist :h registers
.
Der zuletzt kopierte Text wird im Register gespeichert 0
. Sie können darauf zugreifen mit @0
: echo @0
.
Ihr gesuchter Charakter p
befindet sich in diesem Register. Wir weisen es der Variablen zu letter
:
let letter = @0
Als nächstes weisen wir der Variablen die aktuelle Zeile zu line
:
let line = getline('.')
getline()
ist eine integrierte Funktion, die die Zeile zurückgibt, deren Nummer als Argument übergeben wurde, und '.'
die als Nummer der aktuellen Zeile erweitert wird.
Als nächstes weisen wir der Variablen list
eine Liste zu, die jedes Wort der Zeile enthält:
let list = split(line)
split()
ist eine integrierte Funktion, die eine Zeichenfolge aufteilt, wenn ein Leerzeichen gefunden wird (Leerzeichen, Tabulatorzeichen ...). Sie können es an anderen Stellen aufteilen, indem Sie ein zweites Argument angeben. Wenn Sie beispielsweise teilen möchten, wann immer ein Doppelpunkt vorhanden ist, würden Sie verwenden split(line, ':')
.
Für Schleife
Die for
Schleife durchläuft die Variable list
und speichert jedes ihrer Elemente in der Variablen word
:
for word in list
...
endfor
Anschließend wird überprüft, ob der erste Buchstabe von word
der gesuchte Buchstabe ist:
if matchstr(word, '\%1c.') ==# letter
...
endif
matchstr()
ist eine integrierte Funktion, die ein Muster zurückgibt, wenn es in einer Zeichenfolge gefunden wird.
Hier suchen wir nach dem Muster im '\%1c.'
Inneren word
. In einem Vim-Regex \%1c
ist ein Atom mit der Breite Null. Es fügt dem Muster nichts hinzu, sondern teilt der Regex-Engine, die den Regex analysiert, mit, dass unser Muster in der ersten Spalte des Textes beginnt (für weitere Informationen :h /\%c
). Der Punkt am Ende des regulären Ausdrucks bedeutet ein beliebiges Zeichen.
Bedeutet '\%1c.'
also: ein beliebiges Zeichen in der ersten Spalte des Textes und matchstr(word, '\%1c.')
gibt das erste Zeichen von zurück word
.
Um den ersten Buchstaben von word
mit zu vergleichen, verwenden letter
wir den ==#
Operator. Es ist ein Operator, bei dem zwischen Groß- und Kleinschreibung unterschieden wird (unabhängig vom Wert der ignorecase
Option). Sie können auch eine ==?
Groß- und Kleinschreibung verwenden, bei der ==
die Groß- und Kleinschreibung nicht berücksichtigt wird (bei der die Groß- und Kleinschreibung beachtet wird oder die nicht davon abhängt ignorecase
; es wird nicht empfohlen, diese zu verwenden).
Wenn das erste Zeichen von word
ist letter
, bewirkt die Funktion Folgendes:
let col = match(line, word) + 1
Es speichert den Index des ersten Zeichens von word
plus eins in der Variablen col
. match()
ist eine integrierte Funktion, deren Basissyntax lautet match(string, pattern)
und die den Index zurückgibt, in string
dem sie pattern
übereinstimmt. Wir fügen eins hinzu, weil vim mit 0 indiziert.
Schließlich führt es Folgendes aus:
execute "normal! " . col . "|"
execute
ist ein Befehl, der den Inhalt einer Zeichenfolge ausführt, die Sie an ihn übergeben. Hier ist die Zeichenfolge:"normal! " . col . "|"
Der Punkt - Operator verkettet die drei Saiten "normal !"
, col
(es ist eine Zahl , aber Vims Zwang verwandelt es in einen String automatisch), und "|"
.
Angenommen, Ihr gesuchtes Zeichen befindet sich in der 10. Spalte der Zeile. In diesem Fall würde die vorherige Zeichenfolge wie folgt ausgewertet : "normal! 10|"
. execute
Wird also ausgeführt "normal! 10|"
, was dazu führt , dass der normal
Befehl 10|
für uns eingegeben wird.