4

I know that e.g. 50% is a normal mode command to go halfway down a file, but [count]% is line-wise.

How can I get to the halfway point of the line that my cursor is on?

3 Answers 3

3

Well, there is no built in way to do it as far as I know, but out of curiosity I have come up with the following:

nnoremap gl :exe 'normal ' . len(getline('.'))/2 . '\|'<CR>

With gl you will be placed in the "middle" of the line (you know... those odd char counts :)

What it does:

  1. I want to bind a 77| normal command which is "goto 77th char in current line". We have to count proper char count though.
  2. :exe -- execute a command
  3. 'normal ' -- we want to execute normal command and start to combine it from different strings
  4. . len(getline('.'))/2 . -- calculate the half length of a current line and join it with other parts of a normal command with dots (.)
  5. '\|' this normal command should move the cursor to the given char (we have to escape it though as this bar | is also used in vimscript)
  6. <CR> -- emits enter to execute :exe we have constructed

I think there might be an easier way but this one works :)

PS

More bulletproof solution with percentage prefix provided by @Jürgen Krämer

nnoremap gl :<c-u>exe 'normal! ' . (strchars(getline('.')) * v:count1 / 100) . '\|'<cr>

30gl to go to 30% char of the current line.

  1. <c-u> -- removes range symbols that might be added by vim (just in case)
  2. normal! -- executes normal mode command with default not remapped meanings (like if you have remapped | command to do smth else and still want to execute default command)
  3. strchars instead of len -- to properly count length of a unicode line. len gives you byte count.
  4. v:count1 is the built-in variable, count number that you have entered just before pressing normal command itself -- in 50l it would be 50 that is passed to l as v:count1
  5. (strchars(getline('.')) * v:count1 / 100) -- percentage to real char count calculation. So you have a line with 150 length and you have provided 50gl to go to 50% of the line. 150*50/100 will give you half of the line.
6
  • 2
    I think this is what you're alluding to in the second paragraph, but it's possibly worth mentioning explicitly that this code uses byte counts (so it doesn't work well for admittedly contrived examples such as the line ..........éééééééééé).
    – Rich
    Commented Jul 10, 2019 at 10:47
  • 1
    If you want to be able to use a count like you can with %, you can use the predefined variable v:count1: nnoremap gl :<c-u>exe 'normal ' . (len(substitute(getline('.'), '.', 'x', 'g')) * v:count1 / 100) . '\|'<cr>. With this mapping 50gl will put the cursor at half of the line, 25glwill put it at roughly a quarter of the line. Characters with more than one byte are taken care of by reducing all characters to (single byte sized) xs. Commented Jul 10, 2019 at 12:00
  • 2
    Even simpler method for counting chars and not bytes: nnoremap <leader>% :<c-u>exe 'normal ' . (strchars(getline('.')) * v:count1 / 100) . '\|'<cr> Commented Jul 10, 2019 at 12:20
  • 1
    Why not normal! ?
    – D. Ben Knoble
    Commented Jul 10, 2019 at 12:21
  • Indeed, strchars is better then len and v:count1 is the way to go too. And normal! should be used. Sorry, I have just made quick and dirty solution :). But thanks for comments!
    – Maxim Kim
    Commented Jul 10, 2019 at 12:38
6

As of version 8.1.2231 Vim has the gM command which puts your cursor at the middle of a text line. If you supply a count the count is interpreted as the percentage of the line width, e.g., 33gM will put the cursor at roughly one third of the text width.

1

Assume halfway is center of line screen columns.

:h gm moves to window center or as far as possible.

To move to center of a line:

nnoremap <expr> gc virtcol('$')/2 . '<bar>'

:h virtcol() with '$' return 1 + screen columns of current line. :h bar move to count screen column.

IMO, this kind of command is useless most of the time, :h f is the practical way.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.