1

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

foo i()
...
End foo i

with

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)
        return
    endif

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

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

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

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?

4
  • 1
    Should parts end with '\s+(\S*)\(.*\)\s*$'?
    – muru
    Commented Jan 12, 2017 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
    Commented Jan 12, 2017 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
    Commented Jan 12, 2017 at 11:26
  • Ah, ok...thanks. I misunderstood your comment. Yes...that is working (but no idea how and why :))
    – BaRud
    Commented Jan 12, 2017 at 11:28

1 Answer 1

2

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.

6
  • 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
    Commented Jan 12, 2017 at 11:56
  • Like this? '\s+(\S*)\(.*\)?\s*$'
    – muru
    Commented Jan 12, 2017 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
    Commented Jan 12, 2017 at 12:01
  • Ah, the entire (bar) is optional. Then: '\s+(\S*)(\(.*\))?\s*$'
    – muru
    Commented Jan 12, 2017 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
    Commented Jan 12, 2017 at 12:11

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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