I am trying to match a block of fortran, say,

foo i()
End foo i


autocmd CursorMovedI *.f90  :call FixName("foo")

where FixName is:

" FixName: Change Subprogram name {{{1
function! FixName(arg)
    let [buf, l, c, off] = getpos('.')
    call cursor([1, 1, 0])

    let lnum = search('\v\c^\s*' . a:arg . '\s+', 'cnW')
    if !lnum
        call cursor(l, c, off)

    let parts = matchlist(getline(lnum), '\v\c^\s*' . a:arg . '\s+(\S*)\s*$')
    if len(parts) < 2
        call cursor(l, c, off)

    let lnum = search('\v\c^\s*End\s*' . a:arg . '\s+', 'cnW')
    call cursor(l, c, off)
    if !lnum

    call setline(lnum, substitute(getline(lnum), '\v\c^\s*End\s*' . a:arg . '\s+\zs.*', parts[1], ''))

The problem is, with this FixName, I am getting anything after the foo. So, if I have, foo bar(anything), I am ending up with End foo bar(anything). But, I want only the bar (i.e. before the "(").

I have tried to change the last line as:

 call setline(lnum, substitute(getline(lnum), '\v\c^\s*End\s*' . a:arg . '\s+\zs.*[?=\(]', parts[1], ''))

but obviously that's not the correct way. How should I correct it?

  • 1
    Should parts end with '\s+(\S*)\(.*\)\s*$'? – muru Jan 12 '17 at 11:08
  • yes, but I need to terminate it before "(". Say, in python, I would do something like \s+(.*)(?=\(). But, vim is complaining about E866: misplaced ? – BaRud Jan 12 '17 at 11:24
  • I meant you could use the string I provided instead of the one you currently use: let parts = matchlist(getline(lnum), '\v\c^\s*' . a:arg . '\s+(\S*)\(.*\)\s*$'). As for what your Python code does: :h zero-width. – muru Jan 12 '17 at 11:26
  • Ah, ok...thanks. I misunderstood your comment. Yes...that is working (but no idea how and why :)) – BaRud Jan 12 '17 at 11:28

Instead of '\s+(\S*)\s*$' in matching for parts, you could use '\s+(\S*)\(.*\)\s*$'. () in a magic regex (\v) is, of course, used for grouping, so to match for literal parentheses, you need to use \(\). '\s+(\S*)\(.*\)\s*$' thus matches whitespace, followed by non-whitespace, then a pair of parentheses containing anything. So, the grouped part only matches the text before the opening parenthesis.

  • Hi, sorry, as this solves the problem what I have asked for. But, I realize, that I need to make the () things optional. Is it possible to make the ( optional? i.e. it should match the characters until the end of line or the (? – BaRud Jan 12 '17 at 11:56
  • Like this? '\s+(\S*)\(.*\)?\s*$' – muru Jan 12 '17 at 11:57
  • sorry but it is not changing any behavior. what I am looking for is matching foo either for foo or foo(bar) – BaRud Jan 12 '17 at 12:01
  • Ah, the entire (bar) is optional. Then: '\s+(\S*)(\(.*\))?\s*$' – muru Jan 12 '17 at 12:02
  • 1
    Hmm. That regex was greedy, so when \(.*\) became optional, \S* matched it as well. Maybe '\s+(\S{-})(\(.*\))?\s*$', but not sure – muru Jan 12 '17 at 12:11

Your Answer

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.