       lineIsWhitespaceOnly = firstTrailingWhitespacePosition is 0
       position = 0
       for token in tokens
-        updateScopeStack(token.scopes)
+        @updateScopeStack(line, scopeStack, token.scopes)
         hasLeadingWhitespace =  position < firstNonWhitespacePosition
         hasTrailingWhitespace = position + token.value.length > firstTrailingWhitespacePosition
         hasIndentGuide = not mini and showIndentGuide and (hasLeadingWhitespace or lineIsWhitespaceOnly)
         line.push(token.getValueAsHtml({invisibles, hasLeadingWhitespace, hasTrailingWhitespace, hasIndentGuide}))
         position += token.value.length
 
-    popScope() while scopeStack.length > 0
+    @popScope(line, scopeStack) while scopeStack.length > 0
     line.push(htmlEolInvisibles) unless text == ''
     line.push("<span class='fold-marker'/>") if fold
 
     line.push('</div>')
     line.join('')
+
+  @updateScopeStack: (line, scopeStack, desiredScopes) ->
+    excessScopes = scopeStack.length - desiredScopes.length
+    if excessScopes > 0
+      @popScope(line, scopeStack) while excessScopes--
+
+    # pop until common prefix
+    for i in [scopeStack.length..0]
+      break if _.isEqual(scopeStack[0...i], desiredScopes[0...i])
+      @popScope(line, scopeStack)
+
+    # push on top of common prefix until scopeStack == desiredScopes
+    for j in [i...desiredScopes.length]
+      @pushScope(line, scopeStack, desiredScopes[j])
+
+    null
+
+  @pushScope: (line, scopeStack, scope) ->
+    scopeStack.push(scope)
+    line.push("<span class=\"#{scope.replace(/\./g, ' ')}\">")
+
+  @popScope: (line, scopeStack)->
+    scopeStack.pop()
+    line.push("</span>")
 
   @buildEmptyLineHtml: (showIndentGuide, eolInvisibles, htmlEolInvisibles, indentation, activeEditSession, mini) ->
     if not mini and showIndentGuide

    new Array(div.children...)

  htmlForScreenRows: (startRow, endRow) ->
    htmlLines = []
    screenRow = startRow
    for line in @activeEditSession.linesForScreenRows(startRow, endRow)
      htmlLines.push(@htmlForScreenLine(line, screenRow++))
    htmlLines.join('\n\n')

  htmlForScreenLine: (screenLine, screenRow) ->
    { tokens, text, lineEnding, fold, isSoftWrapped } =  screenLine

    scopeStack = []
    line = []

    attributePairs = ''
    attributePairs += " #{attributeName}=\"#{value}\"" for attributeName, value of attributes
    line.push("<div #{attributePairs}>")

    if text == ''
      html = Editor.buildEmptyLineHtml(showIndentGuide, eolInvisibles, htmlEolInvisibles, indentation, activeEditSession, mini)
