I'm attempting to create a syntax file for Python loaded from
$VIM/after/syntax/python.vim that generates rules to highlight "else"
based on context; python allows "else" to be used for "while" and "for"
loops as well as in "try" blocks after "except" entries. I've gotten
fairly close to achieving the behaviour I want, but I'm stuck now and
have not been able to figure out how to resolve some remaining issues.
I've attached the script to this email along with a sample Python file
with some test cases. Note that being able to see a difference in the
"else" coloring is contingent on the color scheme you're using having a
different coloring for "Repeater" and "Conditional" tokens, so I've also
included a screenshot of how things render on my system.

Eric

-- 
-- 
You received this message from the "vim_use" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php

--- 
You received this message because you are subscribed to the Google Groups 
"vim_use" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
For more options, visit https://groups.google.com/d/optout.
" Author: Eric Pruitt
" Description: Context-sensitive highlighting for `else` clauses.

" These are blocks that need to be excluded from the LoopElse and TryElse
" regions to avoid unnecessarily activating them. The current list allows this
" script to work with the default Python syntax file included with Vim (at
" least the one that comes with 7.3 and 7.4) as well as Dmitry Vasiliev's
" [enhanced syntax file](http://www.vim.org/scripts/script.php?script_id=790).
" If highlighting appears to be broken with another syntax file, determine the
" by moving the cursor on top of the improperly highlighted word and executing
" the following command:
"
"   :echo synIDattr(synID(line("."), col("."), 1), "name")
"
" Add the displayed name to the list below, then restart Vim.
let s:excludedRegions = [
\   "pythonDoctestValue",
\   "pythonBytesContent",
\   "pythonBytesError",
\   "pythonDottedName",
\   "pythonFunction",
\]

let s:indentLevels = range(15, 0, -1)
let s:allMatchNames =
\ join([""] + s:indentLevels, ",pythonLoopElse") .
\ join([""] + s:indentLevels, ",pythonTryElse")

let s:allbutList = join(s:excludedRegions, ",")

"syn keyword pythonRepeat contained else
"syn keyword None else

for s:indentLevel in s:indentLevels
    " Remove current pythonLoopElse name from the list of excluded blocks.
    let s:invalidContexts = substitute(s:allMatchNames, ',pythonLoopElse' . 
s:indentLevel . '\>', '', '')

    execute printf(
\       'syn region pythonLoopBlock%i start="^\(    \|\t\)\{%i\}\(for\|while\)" 
end="^\(    \|\t\)\{,%i\}\S\+" transparent keepend contains=ALLBUT,%s%s',
\       s:indentLevel,
\       s:indentLevel,
\       s:indentLevel,
\       s:allbutList,
\       s:invalidContexts)
    execute printf(
\       'syn match pythonLoopElse%i  "^\(    \|\t\)\{%i\}else\>" contained',
\       s:indentLevel,
\       s:indentLevel)
    execute printf('hi def link pythonLoopElse%i Repeat', s:indentLevel)
endfor

for s:indentLevel in s:indentLevels
    let s:invalidContexts = substitute(s:allMatchNames, ',pythonTryElse' . 
s:indentLevel . '\>', '', '')
    execute printf(
\       'syn region pythonTryBlock%i start="^\(    \|\t\)\{%i\}\(except\)" 
end="^\(    \|\t\)\{%i\}\S\+" transparent keepend contains=ALLBUT,%s%s',
\       s:indentLevel,
\       s:indentLevel,
\       s:indentLevel,
\       s:allbutList,
\       s:invalidContexts)
    execute printf(
\       'syn match pythonTryElse%i  "^\(    \)\{%i\}else\>" contained',
\       s:indentLevel,
\       s:indentLevel)
    execute printf('hi def link pythonTryElse%i Exception', s:indentLevel)
endfor
# "else" is never highlighted correctly when the loop blocks are not indented.
while False:
    pass
else:
    pass

if False:
# This works OK
    while False:
        pass
    else:
        pass

# The "else" is not highligted correctly
    while False:
        while False:
            pass
    else:
        pass

# This (still) works OK
    if False:
        pass
    else:
        pass

class Highlight():
# The second function defintion loses its highlighting
    def nothing():
        while False:
            while False:
                pass

    def function():
        pass

<<attachment: rendered-test-cases.png>>

Reply via email to