Vim split causes syntax highlight to turn on - vim

I am trying to write a function to cause vim to open the relative header/source file in a split window.
What I have works (see below) apart from the file it opens in the split doesn't have syntax highlighting.
function! SplitOther()
let s:fname = expand("%:p:r")
if expand("%:e") == "h"
set splitright
exe "vsplit" fnameescape(s:fname . ".cpp")
elseif expand("%:e") == "cpp"
set nosplitright
exe "vsplit" fnameescape(s:fname . ".h")
endif
endfunction
autocmd! BufReadPost *.h,*.cpp call SplitOther()
I have tried appending syntax on to the command (just before the endfunction) but that doesn't seem to want to work.
I think it happens when the file isn't in a buffer before splitting? I'm not 100% sure though.
Edit
I change my function to have allow the definition of file pairs, I'm not sure if it will change my question at all so here's the extended version:
function! SplitOther()
let s:pairs = [ [ "h", "cpp" ], [ "vert", "frag" ] ]
let s:fname = expand("%:p:r")
for [s:left, s:right] in s:pairs
if expand("%:e") == s:left
set splitright
exe "vsplit" fnameescape(s:fname . "." . s:right)
elseif expand("%:e") == s:right
set nosplitright
exe "vsplit" fnameescape(s:fname . "." . s:left)
endif
endfor
endfunction
autocmd! BufReadPost * call SplitOther()

Got it!
When the file was being loaded into the vsplit it's filetype wasn't being set.
I noted that when vsplit is called the new split grabs focus and that is the window that does not have syntax highlighting so you can simply add exe "filetype" "detect" at the end of the function to tell vim to detect the filetype of the current window.
The result:
function! SplitOther()
let s:pairs = [ [ "h", "cpp" ], [ "vert", "frag" ] ]
let s:fname = expand("%:p:r")
for [s:left, s:right] in s:pairs
if expand("%:e") == s:left
set splitright
exe "vsplit" fnameescape(s:fname . "." . s:right)
break
elseif expand("%:e") == s:right
set nosplitright
exe "vsplit" fnameescape(s:fname . "." . s:left)
break
endif
endfor
exe "filetype" "detect"
endfunction
autocmd! BufRead * call SplitOther()

The problem is that filetype detection is triggered by an autocmd, but by default, autocommands do not nest (cp. :help autocmd-nested).
Also, by using :autocmd! with a bang, you're clearing all other such global autocmds; this might affect other customizations or plugins! You should define your own scope via :augroup, then it's safe. Taken together:
augroup MyAltSplitPlugin
autocmd! BufReadPost * nested call SplitOther()
augroup END

Related

Using template files in Vim

I am trying to use a template for Ruby files, by adding this to my .vimrc:
function! RubyTemplate()
" Add pragma comment
call setline(1, '# frozen_string_literal: true')
" Add two empty lines
call append(1, repeat([''], 2))
" Place cursor on line number 3
call cursor(3, 0)
endfunction
autocmd BufNewFile *.rb :call RubyTemplate()
However, this doesn't work and when I open a new Ruby file, it's empty.
Everything works as expected if I issue an :e! afterwards. However, this doesn't work if I add e! to the function, so I have to manually fire it every time.
What am I doing wrong?
You can use a static template file instead of invoking a function.
For instance, you can create a template file for your ruby scripts in your vim directory as ~/.vim/skeletons/ruby.skel, with the desired contents.
1 # frozen_string_literal: true
2
3
Then in your vimrc you should add the following code:
" Skeleton for .rb files
augroup ruby
" Remove all existing autocommands in the group
au!
au BufNewFile *.rb 0r ~/.vim/skeletons/ruby.skel
augroup end
Noah Frederick has an elegant solution that allows us to insert snippets manually or automatically.
It uses ultisnips plugin and two files
" after/plugin/ultisnips_custom.vim
if !exists('g:did_UltiSnips_plugin')
finish
endif
augroup ultisnips_custom
autocmd!
autocmd BufNewFile * silent! call snippet#InsertSkeleton()
augroup END
and
" autoload/snippet.vim
function! s:try_insert(skel)
execute "normal! i_" . a:skel . "\<C-r>=UltiSnips#ExpandSnippet()\<CR>"
if g:ulti_expand_res == 0
silent! undo
endif
return g:ulti_expand_res
endfunction
function! snippet#InsertSkeleton() abort
let filename = expand('%')
" Abort on non-empty buffer or extant file
if !(line('$') == 1 && getline('$') == '') || filereadable(filename)
return
endif
call s:try_insert('skel')
endfunction
In my case, I have done some changes but now if I create an empty python file, for example, I end up with:
An important note: In my case, if vim or neovim is not detecting the filetype correctly, and it can be done with auto commands, your automatic snippet insertion will not work.

How to retain cursor position when using :%!filtercmd in vim?

When I issue a vim command that starts with :%!, such as :%!sort to sort all lines in the buffer, the cursor moves to the first line. How do I preserve the cursor position?
Ultimately, I want to use this command in an autocmd, such as:
augroup filetype_xxx
autocmd!
autocmd BufWrite *.xxx :%!sort
augroup END
Will the same method work in both places?
You can use a mark to remember the current line number (but note that the line contents could change):
augroup filetype_xxx
autocmd!
autocmd BufWrite *.xxx :kk
autocmd BufWrite *.xxx :%!sort
autocmd BufWrite *.xxx :'k
augroup END
I would rather use the Preserve function. Beyond solving your problem in this particular task you can use it for much more.
" preserve function
if !exists('*Preserve')
function! Preserve(command)
try
let l:win_view = winsaveview()
"silent! keepjumps keeppatterns execute a:command
silent! execute 'keeppatterns keepjumps ' . a:command
finally
call winrestview(l:win_view)
endtry
endfunction
endif
augroup filetype_xxx
autocmd!
autocmd BufWrite *.xxx :call Preserve("%!sort")
augroup END
You can also use the "Preserve Function" to perform other useful tasks like:
command! -nargs=0 Reindent :call Preserve('exec "normal! gg=G"')
DelBlankLines')
fun! DelBlankLines() range
if !&binary && &filetype != 'diff'
call Preserve(':%s/\s\+$//e')
call Preserve(':%s/^\n\{2,}/\r/ge')
endif
endfun
endif
command! -nargs=0 DelBlank :call DelBlankLines()
nnoremap <Leader>d :call DelBlankLines()<cr>
" remove trailing spaces
if !exists('*StripTrailingWhitespace')
function! StripTrailingWhitespace()
if !&binary && &filetype != 'diff'
call Preserve(":%s,\\s\\+$,,e")
endif
endfunction
endif
command! Cls call StripTrailingWhitespace()
cnoreabbrev cls Cls
cnoreabbrev StripTrailingSpace Cls

Is there a way to automatically preview a file when the cursor is placed over it in netrw listing?

This is not about hitting ā€˜pā€™ when over the file name , but essentially having the same result by simply placing the cursor over it.
You can remap some motions to a function that populates the preview window according to the current word under the cursor.
Here's a basic example that handles text files and directories:
set nocompatible
set autochdir
" Previewed files are present in the current directory
let g:netrw_keepdir = 0
function! PreviewFile(...)
let l:wordUnderCursor = a:1
if !empty(glob(l:wordUnderCursor))
let l:type = system('file -ib ' . shellescape(l:wordUnderCursor))
if l:type =~# '^text/plain'
silent! execute 'pedit' l:wordUnderCursor
elseif l:type =~# '^inode/directory'
let l:name = tempname()
set noautochdir
silent! execute 'pedit! ' . l:name
wincmd P
normal! ggdG
silent! execute 'r !ls ' . l:wordUnderCursor
normal! ggdd
wincmd w
endif
endif
endfunction
autocmd FileType netrw
\ nnoremap j j:call PreviewFile(expand("<cWORD>"))<CR> |
\ nnoremap k k:call PreviewFile(expand("<cWORD>"))<CR>

Can an autocmd be turned on/off?

I have follwing in my .vimrc to hightlight all words that matches the one on current cursor
autocmd CursorMoved * silent! exe printf('match Search /\<%s\>/', expand('<cword>'))
But sometimes it is a little annoying, so I'd like to map a key to turn on or off it, e.g. <F10>
How can I do this?
Clear the autocommand and remove highlight:
nmap <f8> :autocmd! CursorMoved<cr> :call clearmatches()<cr>
and to turn it back on using a different key:
nmap <f9> :autocmd CursorMoved * silent! exe printf('match Search /\<%s\>/', expand('<cword>'))<cr>
Put the following in your .vimrc:
let g:toggleHighlight = 0
function! ToggleHighlight(...)
if a:0 == 1 "toggle behaviour
let g:toggleHighlight = 1 - g:toggleHighlight
endif
if g:toggleHighlight == 0 "normal action, do the hi
silent! exe printf('match Search /\<%s\>/', expand('<cword>'))
else
"do whatever you need to clear the matches
"or nothing at all, since you are not printing the matches
endif
endfunction
autocmd CursorMoved * call ToggleHighlight()
map <F8> :call ToggleHighlight(1)<CR>
The idea is, if you call the function with an argument it changes the behavior to print/no print.
The autocommand just uses the last setting because the function there is called without an argument.

running python on vim

Over on askubuntu.com I was told how to run python on Vim. I am testing the set up which works with the code 1st or 2nd code python code at using python to solve a non linear equation.
The only thing I have done different was added print(a) as the last line. I ran this yesterday from the shell and it worked perfectly. Could someone let me know what is going wrong?
Ok so I corrected the vimrc with the appropriate question marks,
chmod +x ~/path/to/file/hw6problem2.py
Then from vim I ran
:Shell ./#
but I received the same syntax error again. (Does the file have to be saved as .sh because I can't get any .py files to run?)
dustin#dustin:~$ vim /home/dustin/Documents/School/UVM/Engineering/OrbitalMechanics/hw6problem2.py
File "hw6problem2.py", line 14
a0 = max(s/2, (s - c)/2)
^
SyntaxError: invalid syntax
shell returned 1
Press ENTER or type command to continue
vimrc
syntax on
au BufWinLeave * mkview "records settings
au BufWinEnter * silent loadview "reloads settings
set nu "puts line numbers on
set ic "case insensitive
set foldmethod=syntax "for the latex-suite
set autoread "autoload when files in the buffer have been modified
set autochdir "autochange directory
"set wrap
set wrap
" set lines=50 columns=80
" resizes window
:map g1 :set lines=20<CR>:set columns=80<CR>
:map g2 :set lines=50<CR>:set columns=80<CR>
:map g3 :set lines=50<CR>:set columns=170<CR>
:map <F6> :! firefox % &<CR>
:map E Ea
"set autoindent
set tabstop=4
set shiftwidth=2
set expandtab
set smartindent
"
" Stuff for latex-suite
" REQUIRED. This makes vim invoke Latex-Suite when you open a tex file.
" It also allows you to set different actions for different filetypes
" in ~/.vim/after/ftplugin/*.vim
filetype plugin on
set shellslash
" IMPORTANT: grep will sometimes skip displaying the file name if you
" search in a singe file. This will confuse Latex-Suite. Set your grep
" program to always generate a file-name.
set grepprg=grep\ -nH\ $*
" OPTIONAL: This enables automatic indentation as you type.
filetype indent on
" OPTIONAL: Starting with Vim 7, the filetype of empty .tex files defaults to
" 'plaintex' instead of 'tex', which results in vim-latex not being loaded.
" The following changes the default filetype back to 'tex':
let g:tex_flavor='latex'
let g:Tex_ViewRule_pdf = 'okular'
"""""""""""""""""""""""""""""""""""""""
" => Shell command
"""""""""""""""""""""""""""""""""""""""
command! -complete=shellcmd -nargs=+ Shell call s:RunShellCommand(<q-args>)
function! s:RunShellCommand(cmdline)
let isfirst = 1
let words = []
for word in split(a:cmdline)
if isfirst
let isfirst = 0 " don't change first word (shell command)
else
if word[0] =~ '\v[%#<]'
let word = expand(word)
endif
let word = shellescape(word, 1)
endif
call add(words, word)
endfor
let expanded_cmdline = join(words)
rightbelow new
setlocal buftype=nofile bufhidden=wipe nobuflisted noswapfile nowrap
call setline(1, 'You entered: ' . a:cmdline)
call setline(2, 'Expanded to: ' . expanded_cmdline)
call append(line('$'), substitute(getline(2), '.', '=', 'g'))
silent execute '$read !'. expanded_cmdline
1
endfunction
This is likely to be a python issue.
On a side not, there's a great shell function for executing scripts and redirecting output to vim buffer (split window).
Syntax to execute current script (you should have chmod +x and shebang line):
:Shell ./#
In order to add the function, add this to .vimrc:
command! -complete=shellcmd -nargs=+ Shell call s:RunShellCommand(<q-args>)
function! s:RunShellCommand(cmdline)
let isfirst = 1
let words = []
for word in split(a:cmdline)
if isfirst
let isfirst = 0 " don't change first word (shell command)
else
if word[0] =~ '\v[%#<]'
let word = expand(word)
endif
let word = shellescape(word, 1)
endif
call add(words, word)
endfor
let expanded_cmdline = join(words)
rightbelow new
setlocal buftype=nofile bufhidden=wipe nobuflisted noswapfile nowrap
call setline(1, 'You entered: ' . a:cmdline)
call setline(2, 'Expanded to: ' . expanded_cmdline)
call append(line('$'), substitute(getline(2), '.', '=', 'g'))
silent execute '$read !'. expanded_cmdline
1
endfunction
https://github.com/ruslanosipov/dotfiles/blob/master/.vimrc#L137

Resources