That's a lot of code. ;) What if I said we could compact that whole thing down to a one-line command (and mapping)? Let's take it a step at a time, though.
First, the substitution...
:s/\u/ \l&/g
...will replace each capital letter in the current line with a space and the lower-cased letter. Same pattern/replacement can be used in substitute()
.
Let's try leveraging this.
func! ConvertFromCamelCase()
" get the word to be modified
let l:tgt = expand("<cword>")
" Apply the substitution discussed above to the target then
" throw out the unwanted opening space character.
let l:repl = substitute(l:tgt, '\u', ' \l&', "g")[1:]
" Now do substitution on the line's text that just replaces
" the target word with the modified version. Overwrite the
" buffer line with this.
call setline(".", substitute(getline("."), l:tgt, l:repl, ""))
endfunc
If you run that with the cursor on the name of the function up there you'll get:
func! convert from camel case()
There are some corner cases, though, that can trip this up (e.g. when the target word occurs multiple times in the line an occurrence other than the one under the cursor might get modified). Solving these is very doable but would involve several more lines of function calling code.
There's an easier way. We can leverage a Normal mode command instead of function calls. The answer from @statox mentions use of the ciw
operation and that's exactly what we'll use here:
func! ConvertFromCamelCase()
" First two lines are the same as above
let l:tgt = expand("<cword>")
let l:repl = substitute(l:tgt, '\u', ' \l&', "g")[1:]
" Use normal mode commands to insert the updated word
exe "norm! ciw" . l:repl
endfunc
If you join the functions with each other it doesn't even need to be in a function...
:exe "norm! ciw" . substitute(expand("<cword>"), '\u', ' \l&', "g")[1:]
Now put that in a mapping and you're in business:
:nnoremap <a-x> :exe "norm! ciw" . substitute(expand("<cword>"), '\u', ' \l&', "g")[1:]<cr>
Now, this assumes you are using "CapCase" and not "mixedCase", i.e. the target must start with a capital letter otherwise the first char gets thrown out. If you want this to work with "mixedCase" then you'll have to go back to a function and add a little bit of logic. But shouldn't be any big deal at all.
Update: This should handle CapCase and mixedCase (in the function version)...
let l:repl = tolower(l:tgt[0]) . substitute(l:tgt[1:], '\u', ' \l&', "g")
Obviously, creating a mapping that just calls the function is plenty easy so there's really no disadvantage to using this versus the super compact version.