the goal is to be able to write functions names that follow PEP8 as easily and naturally as writing this sentence.

there are many types of situations that need handling

  • insert _ (underscores) for lines that
    1. start with <optional indentation>def
    2. end with .<optional_start_of_method_name>

only when the cursor is not

  1. directly after a comma (,)
  2. in an inline comment
  3. after the closing parenthesis ) of a function definition or call

is there a plugin that already does that? if not, how can I test for the aforementioned situations in vimscript?

  • Try the match function and expr mappings for a start – D. Ben Knoble May 11 '19 at 19:42

This remap <space> to _ if the line starts with def, which is the key to declare a function in python.

inoremap <expr> <space> getline('.')[0:3] == 'def ' ? "_" : "<space>"

Try also the autocmd way:

autocmd FileType python inoremap <expr> <space> getline('.')[0:3] == 'def ' ? "_" : "<space>"


Perhaps it's better to avoid using '_' between function arguments:

inoremap <expr> <space> getline('.')[0:3] == 'def ' && getline('.') !~ '(' ? "_" : "<space>"


I modified the approach detecting if the line ends with a dot as you ask:

function! IsPythonFunction()
    return getline('.')[0:3] == 'def ' || getline('.')[-1:] == '.'

:inoremap <expr> <space> (IsPythonFunction() && getline('.') !~ '(' ) ? "_" : "<space>" 

Again, I suggest to use the autocmd:

autocmd FileType python inoremap <expr> <space> (IsPythonFunction() && getline('.') !~ '(' ) ? "_" : "<space>" 
  • awesome, is there a way to add an or to that condition? i'm getting 0 or 1 as output with this: autocmd FileType python inoremap <expr> <space> getline('.') =~? '\.\(.\+\)\?' || getline('.')[0:3] == 'def ' ? "_" : "<space>" and parsing error when using parenthesis for the condition. – Wis May 11 '19 at 21:35
  • I modified the post to handle the 'def ' and the '.' at the beginning of the line. It also detect if you start declaring arguments opening a parenthesis. – simo-zz May 12 '19 at 10:10
  • I think you misunderstood what this regex check getline('.') =~? '\.\(.\+\)\?' does. it checks if the line ends with a dot or a dot+an unfinished function/var name. all the slashes are confusing, but that's just vim regex. I just tested your last edit, edit2, it doesn't insert _ instead of space on lines ending with .<optional_unfinished_method_or_var_name>. – Wis May 12 '19 at 15:10
  • My given answer satisfies what you asked in your main question: remap <space> to _ if the line starts with def or . . The second edit inserts _. – simo-zz May 13 '19 at 14:29
  • you're right, I didn't think of indentation and all the situations you can write a method name, to be able list them all, however the question title is clear and not specific. :) I'll edit the list in the question right now. – Wis May 13 '19 at 14:50

I improved upon @simo-zz (currently deleted/hidden) answer to

  1. insert a space directly after a comma and underscores after that
  2. insert underscores after a dot or after a dot + start of a method name
  3. insert underscores after def no matter it's indentation level
function! IsPythonFunction()
    let line = getline('.')
    let coln = col('.')
    let lineUptoCursor = line[0:coln-2]
    return (lineUptoCursor[-1:] != ',') && ((line =~? '\(.\+ \)\?def ') || (line =~? '.\+\.\(.\+\)\?'))
autocmd FileType python inoremap <expr> <space> (IsPythonFunction()) ? "_" : "<space>"

what's left for improvement:

  1. insert spaces not underscores in inline comments
    • harder that it initially seems, needs to exclude cases where the # is inside a string, which probably requires an ast parser
  2. insert spaces not underscores after the colon : which comes after the parenthesis ()

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.