tags:

views:

94

answers:

2

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.

Update

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)

+3  A: 

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>
jamessan
What I want is that mark doesn't do anything, if the current mark is already set.
mb14
Thanks, that's pretty much what I m looking for, I guess I need to mix your script with the ZyX one.
mb14
@mb14 here is this mix, see updated answer. Did not know, that `getpos()[1]` of unset mark is zero.
ZyX
The mix (see ZyX) seems to work, thank you guys.
mb14
+3  A: 

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:

  1. We define a dictionary, which keys contain already set marks (actually we could use a list, but dictionary should be a bit faster).
  2. We define a function that:
    1. Pick next symbol. As getchar may return either a string or a character number, we must convert it back to string.
    2. Checks whether we are going to set a mark (you can have mark with name 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.
    3. Checks whether mark in question was already set by this function, throws a error if it was.
    4. Returns text mC, where C is your mark name.
  3. We define a mapping that uses this function returned value as {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()
ZyX
I was more asking if they were already a script doing that somewhere, than asking someone to write it. Anyway thank you. My only concerns is that is doesn't work. (It doesn't check if a mark is defined but if it has been set within the session)
mb14
Cool, I might post it on the vim website, If you want to add any license beforehand.
mb14
@mb14 This is public domain since I do not want to bother myself with such small amount of code.
ZyX