2009-08-04 6 views
3

J'ai écrit ce script qui remplace de nombreux espaces autour du curseur par un espace. Cela ne fonctionne cependant pas quand je l'utilise sans espaces autour du curseur. Il me semble que Vim ne remplace pas sur un match de largeur nulle.Substitution de la correspondance de largeur nulle dans le script vim

function JustOneSpace() 
    let save_cursor = getpos(".") 
    let pos = searchpos(' \+', 'bc') 
    s/\s*\%#\s*/ /e 
    let save_cursor[2] = pos[1] + 1 
    call setpos('.', save_cursor) 
endfunction 

nmap <space> :call JustOneSpace()<cr> 

Voici quelques exemples (tube | est le curseur):

Cette ligne

hello  |  world 

devient

hello |world 

Mais cette ligne

hello wo|rld 

ne devient pas

hello wo |rld 

Mise à jour: En changeant la fonction à ce qui suit cela fonctionne pour les exemples ci-dessus.

function JustOneSpace() 
    let save_cursor = getpos(".") 
    let pos = searchpos(' *', 'bc') 
    s/\s*\%#\s*/ /e 
    let save_cursor[2] = pos[1] + 1 
    call setpos('.', save_cursor) 
endfunction 

Cette ligne

hello |world 

devient

hello w|orld 

Le problème est que les curseurs se déplace vers le caractère suivant. Il devrait rester au même endroit.

Des pointeurs et/ou des astuces?

Répondre

0

Cette fonction est basée sur le answer.

function JustOneSpace() 
    " Get the current contents of the current line 
    let current_line = getline(".") 

    " Get the current cursor position 
    let cursor_position = getpos(".") 

    " Generate a match using the column number of the current cursor position 
    let matchre = '\s*\%' . cursor_position[2] . 'c\s*' 
    let pos = match(current_line, matchre) + 2 

    " Modify the line by replacing with one space 
    let modified_line = substitute(current_line, matchre, " ", "") 

    " Modify the cursor position to handle the change in string length 
    let cursor_position[2] = pos 

    " Set the line in the window 
    call setline(".", modified_line) 
    " Reset the cursor position 
    call setpos(".", cursor_position) 
endfunction 

lieu en utilisant la différence entre la normale et la ligne modifiée, je trouve la position du premier espace qui correspondent à l'expression régulière de la substitution. Puis je régler la position du curseur sur cette position + 1.

+0

J'ai modifié ma fonction de manière alternative (en calculant le nombre d'espaces avant le curseur avant de changer de ligne). – DrAl

3

Je n'utilise pas vim, mais si vous voulez faire correspondre zéro ou plusieurs espaces, ne devriez-vous pas utiliser ' *' au lieu de ' \+'?

EDIT: concernant le problème de positionnement du curseur: ce que vous faites maintenant est de définir la position au début de l'espace avant de faire la substitution, puis de la déplacer d'une position pour la placer après l'espace. Essayez de régler à la fin du match à la place, comme ceci:

search(' *', 'bce') 

De cette façon, les ajouts ou des suppressions auront lieu avant la position du curseur. Dans la plupart des éditeurs, la position du curseur se déplace automatiquement pour suivre ces changements. Vous ne devriez pas avoir besoin de faire de ces trucs de getpos/setpos.

+0

Alan a raison, vous voulez \ *. En utilisant cette modification, le script se comportera comme vous le décrivez. –

+0

Je viens d'essayer, mais il y a toujours un problème. Je vais mettre à jour la question avec l'exemple. –

4

Je pense que le seul problème avec votre script est que la sauvegarde de la position ne semble pas correcte. Vous pouvez essentiellement faire ce que vous essayez de faire avec:

:s/\s*\%#\s*/ /e 

qui est identique au (bon) code de votre question. Vous pouvez simplement mapper ceci avec:

:nmap <space> :s/\s*\%#\s*/ /e<CR> 

Si vous voulez enregistrer la position, cela devient un peu plus compliqué.Probablement le meilleur pari est d'utiliser quelque chose comme ceci:

function! JustOneSpace() 
    " Get the current contents of the current line 
    let current_line = getline(".") 
    " Get the current cursor position 
    let cursor_position = getpos(".") 
    " Generate a match using the column number of the current cursor position 
    let matchRE = '\(\s*\)\%' . cursor_position[2] . 'c\s*' 
    " Find the number of spaces that precede the cursor 
    let isolate_preceding_spacesRE = '^.\{-}' . matchRE . '.*$' 
    let preceding_spaces = substitute(current_line, isolate_preceding_spacesRE, '\1', "") 
    " Modify the line by replacing with one space 
    let modified_line = substitute(current_line, matchRE, " ", "") 
    " Modify the cursor position to handle the change in string length 
    let cursor_position[2] -= len(preceding_spaces) - 1 
    " Set the line in the window 
    call setline(".", modified_line) 
    " Reset the cursor position 
    call setpos(".", cursor_position) 
endfunction 

La plupart de c'est des commentaires, mais l'essentiel est que vous regardez la longueur de la ligne avant et après la substitution et décider de la nouvelle position du curseur en conséquence. Vous pouvez le faire avec votre méthode en comparant len(getline(".")) avant et après si vous préférez.

Modifier

Si vous voulez que le curseur à la fin après le caractère d'espace, modifier la ligne:

let cursor_position[2] -= len(current_line) - len(modified_line) 

telle qu'elle ressemble à ceci:

let cursor_position[2] -= (len(current_line) - len(modified_line)) - 1 

Modifier (2)

J'ai modifié le script ci-dessus pour considérer vos commentaires de telle sorte que la position du curseur ne soit ajustée que par le nombre d'espaces avant la position du curseur. Cela est fait en créant une deuxième expression régulière qui extrait les espaces précédant le curseur (et rien d'autre) de la ligne, puis en ajustant la position du curseur par le nombre d'espaces.

+0

Cette fonction fonctionne presque. Il y a un problème: il déplacera le curseur vers l'avant du caractère espace au lieu de derrière. –

+0

Ah, je ne savais pas exactement où vous vouliez que le curseur se termine, alors j'en ai pris un au hasard. Voir la modification ci-dessus. – DrAl

+0

Après un peu de recherche supplémentaire, il semble que votre fonction ne fonctionne pas du tout. Il y a beaucoup de positions de curseur possibles entre deux mots s'il y a beaucoup d'espaces. Le curseur doit être déplacé par le nombre d'espaces devant le curseur pour arriver à la bonne position, pas le nombre total d'espaces supprimés. Si vous essayez ceci avec le curseur à d'autres positions entre les mots, vous pouvez le voir par vous-même. Mais je pense que j'ai trouvé un moyen d'obtenir les bons résultats. –

0

Ce simple j'utilise ne presque le même:

nnoremap <leader>6 d/\S<CR>

Placez le curseur jusqu'à l'endroit où vous souhaitez supprimer les espaces et il supprime tous les les espaces après le curseur et le texte suivant.

Questions connexes