Skip to content

Instantly share code, notes, and snippets.

@ChHaeni
Last active April 19, 2024 14:04
Show Gist options
  • Save ChHaeni/749b33f308bffa14f9623c46b6518bd2 to your computer and use it in GitHub Desktop.
Save ChHaeni/749b33f308bffa14f9623c46b6518bd2 to your computer and use it in GitHub Desktop.
Vim mapping to fix missing spaces in R code

Add the function shown in the r-spaces.vim file to your .vimrc file.

A possible mapping could be:

" mapping to fix code in normal mode (with motion: e.g. <leader>ip)
nmap <silent> <leader>x :set opfunc=FixFormatting<CR>g@
" mapping to fix a line of code in normal mode
nnoremap <silent> <leader>xx :normal <leader>x_<CR>
" mapping to fix code in visual selection
vnoremap <silent> <leader>x :<c-u>call FixFormatting('v')<cr><cr>
" use !perl to be able to use skip fail (:perldo fails frequently)
function! FixFormatting(type)
" prefix depending on mode
if a:type == 'line'
let prefix = line("'[") . "," . line("']")
elseif a:type == 'v'
let prefix = "'<,'>"
else
let prefix = ""
endif
" shellescape single quote
let single_quote = "'" . '"' . "'" . '"' . "'"
""" don't match here
" don't match inside single quotes (skip escaped single quotes)
let inside_single_quotes = single_quote . '(?:[^' . single_quote . ']|[\\]' . single_quote . ')*' . single_quote . '(*SKIP)(*FAIL)'
" don't match inside double quotes (skip escaped double quotes)
let inside_double_quotes = '"(?:[^"]|[\\]")*"(*SKIP)(*FAIL)'
" don't match inside backticks
let inside_backticks = '`(?:[^`]|[\\]`)*`(*SKIP)(*FAIL)'
" don't match after comment
let after_comment = '\#.*(*SKIP)(*FAIL)'
" don't match inside %.*%
let inside_percent = '\%[^\%]*\%(*SKIP)(*FAIL)'
""" construct command parts
" first part of command
let first_command = prefix . '!perl -p'
" first part of perl command
let first_perl = ' -e ' . "'" . 's/' . inside_single_quotes . '|' . inside_double_quotes . '|' . inside_backticks . '|' . after_comment . '|' . inside_percent . '|'
" first part of perl command without percent part
let first_perl_noperc = ' -e ' . "'" . 's/' . inside_single_quotes . '|' . inside_double_quotes . '|' . inside_backticks . '|' . after_comment . '|'
" last part of perl command (perl commands end with ;)
let last_perl = ";'"
""" allow the following characters before the match of some operators
let lookahead_char = '(?:\w|\)|}|\])\K'
""" start fixing command
" fix ,
let fix_comma = ',[^\S\r\n]*/, /g'
" fix = and == != <= >= :=
let fix_equal = lookahead_char . '[^\S\r\n]*((:|=|\!|<|>|)=)[^\S\r\n]*/ \1 /g'
" fix < > <- <<-
let fix_assign = lookahead_char . '[^\S\r\n]*(<<?-?|>)(?\!=)[^\S\r\n]*/ \1 /g'
" fix + - (binary operators only)
let fix_plus = lookahead_char . '[^\S\r\n]*(\+|-)[^\S\r\n]*/ \1 /g'
" fix * / ^
let fix_times = lookahead_char . '[^\S\r\n]*(\^|\*|\/)[^\S\r\n]*/ \1 /g'
" fix & | && ||
let fix_logic = '[^\S\r\n]*(&&?|\|\|?)[^\S\r\n]*/ \1 /g'
" fix ){ )\w )(
let fix_paren = '\)({|\w|\()/\) \1/g'
" fix for( if( while(
let fix_cond = '\W\K(for|if|while)\(/\1 \(/g'
" fix }else{
let fix_else = '}[^\S\r\n]*else[^\S\r\n]*{/} else {/g'
" fix %.*%
let fix_perc = '[^\S\r\n]*(\%[^\%]*\%)[^\S\r\n]*/ \1 /g'
execute first_command .
\ first_perl . fix_comma . last_perl .
\ first_perl . fix_equal . last_perl .
\ first_perl . fix_assign . last_perl .
\ first_perl . fix_plus . last_perl .
\ first_perl . fix_times . last_perl .
\ first_perl . fix_logic . last_perl .
\ first_perl . fix_paren . last_perl .
\ first_perl . fix_cond . last_perl .
\ first_perl . fix_else . last_perl .
\ first_perl_noperc . fix_perc . last_perl
endfunction
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment