5

I'm writing a report in LaTeX that I keep in a Git repository. In order to make the most out of Git, I would like to keep each sentence on its own line. I.e. for each dot, exclamation mark and question mark - while I'm in insert mode - I would like vim automatically to insert a newline.

However, I only want this to happen in the body of the text and not between {}, [], (), "" or '' because in LaTeX, I may want to write filenames or commands between these characters.

Is there any way I can achieve this with a key mapping in insert mode, or is there another preferred way of doing this?

  • 1
    You could… simply press <CR> when needed. – romainl Oct 6 '16 at 7:23
  • @romainl Thank you for your reply. Yes I could simply press Enter but since I'm not used to pressing Enter every type I press . I feel that it would be simpler to have vim do it for me. That way, I would not forget it. – lklun Oct 6 '16 at 7:27
  • 3
    @statox The OP is talking about semantic linefeeds. If you are hard-wrapping lines, it makes viewing (line-based) diffs easier if each sentence starts a new line. – Rich Oct 6 '16 at 8:33
  • 1
    @statox ...and an alternative solution to that problem is to use soft-wrapped lines and Git's --word-diff. – Rich Oct 6 '16 at 8:40
  • 1
    You can probably use the syntax highlighting information to do this. Can you post some LaTeX example where you do and don't want automatic newlines (I am not that familiar with LaTeX). – Martin Tournoij Oct 7 '16 at 0:13
3

Here is a solution which seems to be working (note the word seems I didn't test it extensively so it might not work in some cases) :

function! InsertDot(char)
    " Save the cursor position
    let save_pos=getpos('.')

    " Try to yank inner braces
    call setreg('z', "")
    normal "zyi(
    normal "zyi[
    normal "zyi"
    normal "zyi'

    if ( getreg('z') == "" )
    " If nothing was yanked insert the character and a new line
        execute "normal! i" . a:char . "^M"
        execute "startinsert"
    else
    " If something was yanked insert the dot
    " (messy workaround to get back to the correct position)
        call setpos('.', save_pos)
        execute "normal! i" . a:char
        execute "startinsert"
        let save_pos[2] = save_pos[2]+1
        call setpos('.', save_pos)
    endif
endfunction

inoremap . <c-o>:call InsertDot('.')<CR>
inoremap ! <c-o>:call InsertDot('!')<CR>

The characters must be mapped in insert mode to call the function. The function will try to determine if the cursor is between braces and add the character and a new line or only the character accordingly.

Note that the function uses a crappy workaround to preserve the cursor position. I'm pretty sure it can be improved.


Otherwise to follow your comment you can use this:

inoremap . .^M
inoremap \. .

To make . insert a dot and a new line and \ . insert only a dot.


Important note

All the occurences of ^M in the code must be added with CTRL+vEnter

  • 2
    Sorry for my late reply! Both solutions work for me. I tried the latter for a while, but it made it difficult to write "e.g.", "i.e." and so on. I will use InsertDot(). Thanks! – lklun Nov 6 '16 at 15:08

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.