I've started to write my first vim plugin, a simple timer. I want to be able to set a timer for an arbitrary amount of time, and have it notify me once that time has passed. I've got it all working, but right now, I'm using echom (or echoerr) to display a message like "timer expired". What I want to do is draw some more attention to the fact that the timer has expired, either by using quickfix or the preview window. I've looked around, and short of arbitrarily setting an error string and using setqflist, I can't really think of anything.

Something I'd also be happy with is the statusline flashing up or something.

How would the more experienced vimscript ninja go about this? Ideally, I'd have something flash, so it draws attention. I'll do some more digging on how I can do that, but in case someone can point me in the right direction, that'd be greatly appreciated.

Just to give you an idea of where I stand in terms of ability: I've been using vim as my main/only editor for about 3 years now. Using vim is not an issue at all. Configuring isn't a problem, either. When it comes to writing plugins, this is my first real attempt. This is what I've written thusfar:

let s:timer_callback = get(g:, 'etimer_callback', 'NotifyTimer')

let s:factors = {
            \"ms": 1,
            \"s": 1000,
            \"m": 60 * 1000,
            \"h": 60 * 60 * 1000,
let s:active_timers = {}

function NotifyTimer(timer_id)
    let l:timer_interval = remove(s:active_timers, a:timer_id)
    call timer_stop(a:timer_id)
    echom printf("Timer %d (%s) expired!", a:timer_id, l:timer_interval)

function! s:start_timer(i)
    let l:interval = s:parse_interval(a:i)
    if l:interval == -1
        return -1
    let l:timer = timer_start(l:interval, s:timer_callback)
    let s:active_timers[l:timer] = a:i
    echo printf("Timer %d set", l:timer)

function s:parse_interval(i)
    if a:i!~#"[smh]$"
        echoerr printf("Invalid interval %s, expected format \d+(ms|s|m|h)$", a:i)
        return -1
    let l:len = strlen(trim(a:i))
    let l:unit_idx = 1
    if a:i=~#"ms$"
        let l:unit_idx = 2
    let l:split_idx = l:len - l:unit_idx
    let l:unit = strpart(a:i, l:split_idx, l:unit_idx)
    let l:interval = str2nr(strpart(a:i, 0, l:split_idx))
    let l:interval = l:interval * get(s:factors, l:unit, 1)
    return l:interval

function s:list_timers()
    for key in keys(s:active_timers)
        echo printf("%d -> %s", key, s:active_timers[key])

function s:cancel_timers()
    let s:active_timers = {}
    call timer_stopall()

Begin a golang dev, I'm really annoyed by the use of a global dictionary. Can't imagine that being safe. I know vim is mostly single threaded when it comes to its scripts, but can't hurt mentioning that concern, and see if it's something I should work on.

| improve this question | | | | |
  • I might use the preview window, if possible. – D. Ben Knoble Jan 23 '19 at 15:25
  • @D.BenKnoble I've done some googling to find out how that would work, but I've come up empty so far. I'd need to pedit and read the message into the buffer somehow. Not sure how to do that TBH – Elias Van Ootegem Jan 23 '19 at 15:43

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.