Reputation: 22596
Is there anyway (internal or via a plugin) to prevent marks to be overridden ? I mean a way so you can't set a mark if it's already used (I'm thinking especially of global marks).
I'm thinking of adding them in my vimrc or session, but I would prefer another way.
Don't send me a script to do it. I can do it myself, my question was more if there is a hidden way in VIM to do it or if I had to write a script myself. The answer is apparently no.
Thanks anyway to people who already sent me a script. I'll use them to write my own one (as the scripts sent are not exactly what I want)
Upvotes: 2
Views: 670
Reputation: 53604
You may remap the m
with custom function:
let s:marks={}
function s:SetMark()
let m=getchar()
if type(m)==type(0)
let m=nr2char(m)
endif
if m=~#'^[a-zA-Z]$'
if has_key(s:marks, m)
throw "Mark ".m."is arleady set"
endif
let s:marks[m]=1
endif
return "m".m
endfunction
nnoremap <expr> m <SID>SetMark()
This function will prevent you from remapping mark. That is how it works:
getchar
may return either a string or a character number, we must convert it back to string.a
, but not with name %
). If you try to set mark %
, it would be ignored by vim, so no need to keep useless keys. And no need to prevent you from using m'
, m[
and m]
since we cannot prevent redefining them by vim itself.mC
, where C
is your mark name.{rhs}
.Note that this will not prevent somebody from redefining this mark by normal!
(but not normal
without a bang) command, nnoremap
(but not nmap
) mapping or something similar.
UPDATE: Modified version of s:SetMark:
function s:SetMark()
let m=getchar()
if type(m)==type(0)
let m=nr2char(m)
endif
if m=~#'^[A-Z]$'
let pos=getpos("'".m)
if pos[1]
echohl Error
echon "Mark ".m." is arleady set. Overwrite?"
echohl None
let c=getchar()
if type(c)==type(0)
let c=nr2char(c)
endif
echo
if c!=?'y'
return "<C-l>"
endif
endif
endif
return "m".m
endfunction
nnoremap <special><expr> m <SID>SetMark()
Upvotes: 6
Reputation: 42647
You can prevent marks from being changed while you run a specific command. See :lockmarks.
There isn't a way to prevent them from being overridden, but you could use a function that asks for the mark to use, informs you if that's already used, and prompts for another mark.
fun! SetMark()
let mark = ''
while mark == ''
call inputsave()
let mark = input('Mark to set (Enter to cancel)? ')
call inputrestore()
if mark == ''
return
endif
if mark !~# '^[A-Z]$'
echohl Error
echo "Invalid mark name. Must be a capital letter."
echohl None
let mark = ''
continue
endif
let pos = getpos("'" . mark)
if pos[1] != 0 " Used mark
let fname = fnamemodify(bufname(pos[0]), ':~:.')
call inputsave()
let yn = input('Mark already set for ' . fname . '. Overwrite? (y/n) ')
call inputrestore()
if yn !~? '^y'
let mark = ''
endif
endif
endwhile
exe 'normal m' . mark
endfun
nnoremap <F2> :call SetMark()<CR>
Upvotes: 4