1d0825bca7fe65beaee391d30da42e937db621564Steve Block/*
2d0825bca7fe65beaee391d30da42e937db621564Steve Block * Copyright (C) 2009 Google Inc. All rights reserved.
3d0825bca7fe65beaee391d30da42e937db621564Steve Block * Copyright (C) 2009 Apple Inc. All rights reserved.
4d0825bca7fe65beaee391d30da42e937db621564Steve Block *
5d0825bca7fe65beaee391d30da42e937db621564Steve Block * Redistribution and use in source and binary forms, with or without
6d0825bca7fe65beaee391d30da42e937db621564Steve Block * modification, are permitted provided that the following conditions are
7d0825bca7fe65beaee391d30da42e937db621564Steve Block * met:
8d0825bca7fe65beaee391d30da42e937db621564Steve Block *
9d0825bca7fe65beaee391d30da42e937db621564Steve Block *     * Redistributions of source code must retain the above copyright
10d0825bca7fe65beaee391d30da42e937db621564Steve Block * notice, this list of conditions and the following disclaimer.
11d0825bca7fe65beaee391d30da42e937db621564Steve Block *     * Redistributions in binary form must reproduce the above
12d0825bca7fe65beaee391d30da42e937db621564Steve Block * copyright notice, this list of conditions and the following disclaimer
13d0825bca7fe65beaee391d30da42e937db621564Steve Block * in the documentation and/or other materials provided with the
14d0825bca7fe65beaee391d30da42e937db621564Steve Block * distribution.
15d0825bca7fe65beaee391d30da42e937db621564Steve Block *     * Neither the name of Google Inc. nor the names of its
16d0825bca7fe65beaee391d30da42e937db621564Steve Block * contributors may be used to endorse or promote products derived from
17d0825bca7fe65beaee391d30da42e937db621564Steve Block * this software without specific prior written permission.
18d0825bca7fe65beaee391d30da42e937db621564Steve Block *
19d0825bca7fe65beaee391d30da42e937db621564Steve Block * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20d0825bca7fe65beaee391d30da42e937db621564Steve Block * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21d0825bca7fe65beaee391d30da42e937db621564Steve Block * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22d0825bca7fe65beaee391d30da42e937db621564Steve Block * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23d0825bca7fe65beaee391d30da42e937db621564Steve Block * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24d0825bca7fe65beaee391d30da42e937db621564Steve Block * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25d0825bca7fe65beaee391d30da42e937db621564Steve Block * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26d0825bca7fe65beaee391d30da42e937db621564Steve Block * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27d0825bca7fe65beaee391d30da42e937db621564Steve Block * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28d0825bca7fe65beaee391d30da42e937db621564Steve Block * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29d0825bca7fe65beaee391d30da42e937db621564Steve Block * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30d0825bca7fe65beaee391d30da42e937db621564Steve Block */
31d0825bca7fe65beaee391d30da42e937db621564Steve Block
32d0825bca7fe65beaee391d30da42e937db621564Steve BlockWebInspector.TextEditorHighlighter = function(textModel, damageCallback)
33d0825bca7fe65beaee391d30da42e937db621564Steve Block{
34d0825bca7fe65beaee391d30da42e937db621564Steve Block    this._textModel = textModel;
35692e5dbf12901edacf14812a6fae25462920af42Steve Block    this._tokenizer = WebInspector.SourceTokenizer.Registry.getInstance().getTokenizer("text/html");
36692e5dbf12901edacf14812a6fae25462920af42Steve Block    this._damageCallback = damageCallback;
3781bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    this._highlightChunkLimit = 1000;
38d0825bca7fe65beaee391d30da42e937db621564Steve Block}
39d0825bca7fe65beaee391d30da42e937db621564Steve Block
40d0825bca7fe65beaee391d30da42e937db621564Steve BlockWebInspector.TextEditorHighlighter.prototype = {
41d0825bca7fe65beaee391d30da42e937db621564Steve Block    set mimeType(mimeType)
42d0825bca7fe65beaee391d30da42e937db621564Steve Block    {
43d0825bca7fe65beaee391d30da42e937db621564Steve Block        var tokenizer = WebInspector.SourceTokenizer.Registry.getInstance().getTokenizer(mimeType);
442bde8e466a4451c7319e3a072d118917957d6554Steve Block        if (tokenizer)
45d0825bca7fe65beaee391d30da42e937db621564Steve Block            this._tokenizer = tokenizer;
46dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    },
47dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
4881bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    set highlightChunkLimit(highlightChunkLimit)
4981bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    {
5081bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch        this._highlightChunkLimit = highlightChunkLimit;
5181bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    },
5281bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch
5381bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    highlight: function(endLine, opt_forceRun)
54d0825bca7fe65beaee391d30da42e937db621564Steve Block    {
55d0825bca7fe65beaee391d30da42e937db621564Steve Block        // First check if we have work to do.
562bde8e466a4451c7319e3a072d118917957d6554Steve Block        var state = this._textModel.getAttribute(endLine - 1, "highlight");
572bde8e466a4451c7319e3a072d118917957d6554Steve Block        if (state && state.postConditionStringified) {
582bde8e466a4451c7319e3a072d118917957d6554Steve Block            // Last line is highlighted, just exit.
59d0825bca7fe65beaee391d30da42e937db621564Steve Block            return;
602bde8e466a4451c7319e3a072d118917957d6554Steve Block        }
61d0825bca7fe65beaee391d30da42e937db621564Steve Block
62d0825bca7fe65beaee391d30da42e937db621564Steve Block        this._requestedEndLine = endLine;
63d0825bca7fe65beaee391d30da42e937db621564Steve Block
6481bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch        if (this._highlightTimer && !opt_forceRun) {
65d0825bca7fe65beaee391d30da42e937db621564Steve Block            // There is a timer scheduled, it will catch the new job based on the new endLine set.
66d0825bca7fe65beaee391d30da42e937db621564Steve Block            return;
67d0825bca7fe65beaee391d30da42e937db621564Steve Block        }
68d0825bca7fe65beaee391d30da42e937db621564Steve Block
692bde8e466a4451c7319e3a072d118917957d6554Steve Block        // We will be highlighting. First rewind to the last highlighted line to gain proper highlighter context.
702bde8e466a4451c7319e3a072d118917957d6554Steve Block        var startLine = endLine;
712bde8e466a4451c7319e3a072d118917957d6554Steve Block        while (startLine > 0) {
722bde8e466a4451c7319e3a072d118917957d6554Steve Block            var state = this._textModel.getAttribute(startLine - 1, "highlight");
732bde8e466a4451c7319e3a072d118917957d6554Steve Block            if (state && state.postConditionStringified)
742bde8e466a4451c7319e3a072d118917957d6554Steve Block                break;
752bde8e466a4451c7319e3a072d118917957d6554Steve Block            startLine--;
762bde8e466a4451c7319e3a072d118917957d6554Steve Block        }
77d0825bca7fe65beaee391d30da42e937db621564Steve Block
782bde8e466a4451c7319e3a072d118917957d6554Steve Block        // Do small highlight synchronously. This will provide instant highlight on PageUp / PageDown, gentle scrolling.
792bde8e466a4451c7319e3a072d118917957d6554Steve Block        this._highlightInChunks(startLine, endLine);
80d0825bca7fe65beaee391d30da42e937db621564Steve Block    },
81d0825bca7fe65beaee391d30da42e937db621564Steve Block
8281bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    updateHighlight: function(startLine, endLine)
8381bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    {
842bde8e466a4451c7319e3a072d118917957d6554Steve Block        // Start line was edited, we should highlight everything until endLine.
852bde8e466a4451c7319e3a072d118917957d6554Steve Block        this._clearHighlightState(startLine);
862bde8e466a4451c7319e3a072d118917957d6554Steve Block
872bde8e466a4451c7319e3a072d118917957d6554Steve Block        if (startLine) {
882bde8e466a4451c7319e3a072d118917957d6554Steve Block            var state = this._textModel.getAttribute(startLine - 1, "highlight");
892bde8e466a4451c7319e3a072d118917957d6554Steve Block            if (!state || !state.postConditionStringified) {
902bde8e466a4451c7319e3a072d118917957d6554Steve Block                // Highlighter did not reach this point yet, nothing to update. It will reach it on subsequent timer tick and do the job.
912bde8e466a4451c7319e3a072d118917957d6554Steve Block                return false;
922bde8e466a4451c7319e3a072d118917957d6554Steve Block            }
9381bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch        }
9481bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch
952bde8e466a4451c7319e3a072d118917957d6554Steve Block        var restored = this._highlightLines(startLine, endLine);
962bde8e466a4451c7319e3a072d118917957d6554Steve Block        if (!restored) {
972bde8e466a4451c7319e3a072d118917957d6554Steve Block            for (var i = this._lastHighlightedLine; i < this._textModel.linesCount; ++i) {
982bde8e466a4451c7319e3a072d118917957d6554Steve Block                var state = this._textModel.getAttribute(i, "highlight");
992bde8e466a4451c7319e3a072d118917957d6554Steve Block                if (!state && i > endLine)
1002bde8e466a4451c7319e3a072d118917957d6554Steve Block                    break;
1012bde8e466a4451c7319e3a072d118917957d6554Steve Block                this._textModel.setAttribute(i, "highlight-outdated", state);
10281bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch                this._textModel.removeAttribute(i, "highlight");
1032bde8e466a4451c7319e3a072d118917957d6554Steve Block            }
10481bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch
1052bde8e466a4451c7319e3a072d118917957d6554Steve Block            if (this._highlightTimer) {
1062bde8e466a4451c7319e3a072d118917957d6554Steve Block                clearTimeout(this._highlightTimer);
1072bde8e466a4451c7319e3a072d118917957d6554Steve Block                this._requestedEndLine = endLine;
1082bde8e466a4451c7319e3a072d118917957d6554Steve Block                this._highlightTimer = setTimeout(this._highlightInChunks.bind(this, this._lastHighlightedLine, this._requestedEndLine), 10);
1092bde8e466a4451c7319e3a072d118917957d6554Steve Block            }
11081bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch        }
1112bde8e466a4451c7319e3a072d118917957d6554Steve Block        return restored;
11281bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    },
11381bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch
1142bde8e466a4451c7319e3a072d118917957d6554Steve Block    _highlightInChunks: function(startLine, endLine)
115d0825bca7fe65beaee391d30da42e937db621564Steve Block    {
116d0825bca7fe65beaee391d30da42e937db621564Steve Block        delete this._highlightTimer;
117d0825bca7fe65beaee391d30da42e937db621564Steve Block
118d0825bca7fe65beaee391d30da42e937db621564Steve Block        // First we always check if we have work to do. Could be that user scrolled back and we can quit.
1192bde8e466a4451c7319e3a072d118917957d6554Steve Block        var state = this._textModel.getAttribute(this._requestedEndLine - 1, "highlight");
1202bde8e466a4451c7319e3a072d118917957d6554Steve Block        if (state && state.postConditionStringified)
121d0825bca7fe65beaee391d30da42e937db621564Steve Block            return;
122d0825bca7fe65beaee391d30da42e937db621564Steve Block
123d0825bca7fe65beaee391d30da42e937db621564Steve Block        if (this._requestedEndLine !== endLine) {
124d0825bca7fe65beaee391d30da42e937db621564Steve Block            // User keeps updating the job in between of our timer ticks. Just reschedule self, don't eat CPU (they must be scrolling).
1252bde8e466a4451c7319e3a072d118917957d6554Steve Block            this._highlightTimer = setTimeout(this._highlightInChunks.bind(this, startLine, this._requestedEndLine), 100);
126d0825bca7fe65beaee391d30da42e937db621564Steve Block            return;
127d0825bca7fe65beaee391d30da42e937db621564Steve Block        }
128d0825bca7fe65beaee391d30da42e937db621564Steve Block
12981bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch        // The textModel may have been already updated.
13081bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch        if (this._requestedEndLine > this._textModel.linesCount)
13181bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch            this._requestedEndLine = this._textModel.linesCount;
13281bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch
1332bde8e466a4451c7319e3a072d118917957d6554Steve Block        this._highlightLines(startLine, this._requestedEndLine);
134d0825bca7fe65beaee391d30da42e937db621564Steve Block
135d0825bca7fe65beaee391d30da42e937db621564Steve Block        // Schedule tail highlight if necessary.
136dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        if (this._lastHighlightedLine < this._requestedEndLine)
1372bde8e466a4451c7319e3a072d118917957d6554Steve Block            this._highlightTimer = setTimeout(this._highlightInChunks.bind(this, this._lastHighlightedLine, this._requestedEndLine), 10);
138d0825bca7fe65beaee391d30da42e937db621564Steve Block    },
139d0825bca7fe65beaee391d30da42e937db621564Steve Block
1402bde8e466a4451c7319e3a072d118917957d6554Steve Block    _highlightLines: function(startLine, endLine)
141d0825bca7fe65beaee391d30da42e937db621564Steve Block    {
1422bde8e466a4451c7319e3a072d118917957d6554Steve Block        // Restore highlighter context taken from previous line.
1432bde8e466a4451c7319e3a072d118917957d6554Steve Block        var state = this._textModel.getAttribute(startLine - 1, "highlight");
1442bde8e466a4451c7319e3a072d118917957d6554Steve Block        var postConditionStringified = state ? state.postConditionStringified : JSON.stringify(this._tokenizer.initialCondition);
145dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
1462bde8e466a4451c7319e3a072d118917957d6554Steve Block        var tokensCount = 0;
1472bde8e466a4451c7319e3a072d118917957d6554Steve Block        for (var lineNumber = startLine; lineNumber < endLine; ++lineNumber) {
1482bde8e466a4451c7319e3a072d118917957d6554Steve Block            var state = this._selectHighlightState(lineNumber, postConditionStringified);
1492bde8e466a4451c7319e3a072d118917957d6554Steve Block            if (state.postConditionStringified) {
1502bde8e466a4451c7319e3a072d118917957d6554Steve Block                // This line is already highlighted.
1512bde8e466a4451c7319e3a072d118917957d6554Steve Block                postConditionStringified = state.postConditionStringified;
15281bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch            } else {
1532bde8e466a4451c7319e3a072d118917957d6554Steve Block                var lastHighlightedColumn = 0;
1542bde8e466a4451c7319e3a072d118917957d6554Steve Block                if (state.midConditionStringified) {
1552bde8e466a4451c7319e3a072d118917957d6554Steve Block                    lastHighlightedColumn = state.lastHighlightedColumn;
1562bde8e466a4451c7319e3a072d118917957d6554Steve Block                    postConditionStringified = state.midConditionStringified;
1572bde8e466a4451c7319e3a072d118917957d6554Steve Block                }
15881bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch
1592bde8e466a4451c7319e3a072d118917957d6554Steve Block                var line = this._textModel.line(lineNumber);
1602bde8e466a4451c7319e3a072d118917957d6554Steve Block                this._tokenizer.line = line;
1612bde8e466a4451c7319e3a072d118917957d6554Steve Block                this._tokenizer.condition = JSON.parse(postConditionStringified);
1622bde8e466a4451c7319e3a072d118917957d6554Steve Block
1632bde8e466a4451c7319e3a072d118917957d6554Steve Block                // Highlight line.
1642bde8e466a4451c7319e3a072d118917957d6554Steve Block                do {
1652bde8e466a4451c7319e3a072d118917957d6554Steve Block                    var newColumn = this._tokenizer.nextToken(lastHighlightedColumn);
1662bde8e466a4451c7319e3a072d118917957d6554Steve Block                    var tokenType = this._tokenizer.tokenType;
1672bde8e466a4451c7319e3a072d118917957d6554Steve Block                    if (tokenType)
1682bde8e466a4451c7319e3a072d118917957d6554Steve Block                        state[lastHighlightedColumn] = { length: newColumn - lastHighlightedColumn, tokenType: tokenType };
1692bde8e466a4451c7319e3a072d118917957d6554Steve Block                    lastHighlightedColumn = newColumn;
1702bde8e466a4451c7319e3a072d118917957d6554Steve Block                    if (++tokensCount > this._highlightChunkLimit)
1712bde8e466a4451c7319e3a072d118917957d6554Steve Block                        break;
1722bde8e466a4451c7319e3a072d118917957d6554Steve Block                } while (lastHighlightedColumn < line.length);
1732bde8e466a4451c7319e3a072d118917957d6554Steve Block
1742bde8e466a4451c7319e3a072d118917957d6554Steve Block                postConditionStringified = JSON.stringify(this._tokenizer.condition);
1752bde8e466a4451c7319e3a072d118917957d6554Steve Block
1762bde8e466a4451c7319e3a072d118917957d6554Steve Block                if (lastHighlightedColumn < line.length) {
1772bde8e466a4451c7319e3a072d118917957d6554Steve Block                    // Too much work for single chunk - exit.
1782bde8e466a4451c7319e3a072d118917957d6554Steve Block                    state.lastHighlightedColumn = lastHighlightedColumn;
1792bde8e466a4451c7319e3a072d118917957d6554Steve Block                    state.midConditionStringified = postConditionStringified;
18081bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch                    break;
1812bde8e466a4451c7319e3a072d118917957d6554Steve Block                } else {
1822bde8e466a4451c7319e3a072d118917957d6554Steve Block                    delete state.lastHighlightedColumn;
1832bde8e466a4451c7319e3a072d118917957d6554Steve Block                    delete state.midConditionStringified;
1842bde8e466a4451c7319e3a072d118917957d6554Steve Block                    state.postConditionStringified = postConditionStringified;
1852bde8e466a4451c7319e3a072d118917957d6554Steve Block                }
1862bde8e466a4451c7319e3a072d118917957d6554Steve Block            }
1872bde8e466a4451c7319e3a072d118917957d6554Steve Block
1882bde8e466a4451c7319e3a072d118917957d6554Steve Block            var nextLineState = this._textModel.getAttribute(lineNumber + 1, "highlight");
1892bde8e466a4451c7319e3a072d118917957d6554Steve Block            if (nextLineState && nextLineState.preConditionStringified === state.postConditionStringified) {
1902bde8e466a4451c7319e3a072d118917957d6554Steve Block                // Following lines are up to date, no need re-highlight.
1912bde8e466a4451c7319e3a072d118917957d6554Steve Block                ++lineNumber;
1922bde8e466a4451c7319e3a072d118917957d6554Steve Block                this._damageCallback(startLine, lineNumber);
1932bde8e466a4451c7319e3a072d118917957d6554Steve Block
1942bde8e466a4451c7319e3a072d118917957d6554Steve Block                // Advance the "pointer" to the last highlighted line within the given chunk.
1952bde8e466a4451c7319e3a072d118917957d6554Steve Block                for (; lineNumber < endLine; ++lineNumber) {
1962bde8e466a4451c7319e3a072d118917957d6554Steve Block                    var state = this._textModel.getAttribute(lineNumber, "highlight");
1972bde8e466a4451c7319e3a072d118917957d6554Steve Block                    if (!state || !state.postConditionStringified)
1982bde8e466a4451c7319e3a072d118917957d6554Steve Block                        break;
19981bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch                }
2002bde8e466a4451c7319e3a072d118917957d6554Steve Block                this._lastHighlightedLine = lineNumber;
2012bde8e466a4451c7319e3a072d118917957d6554Steve Block                return true;
20281bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch            }
203d0825bca7fe65beaee391d30da42e937db621564Steve Block        }
204d0825bca7fe65beaee391d30da42e937db621564Steve Block
2052bde8e466a4451c7319e3a072d118917957d6554Steve Block        this._damageCallback(startLine, lineNumber);
206dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        this._lastHighlightedLine = lineNumber;
2072bde8e466a4451c7319e3a072d118917957d6554Steve Block        return false;
2082bde8e466a4451c7319e3a072d118917957d6554Steve Block    },
2092bde8e466a4451c7319e3a072d118917957d6554Steve Block
2102bde8e466a4451c7319e3a072d118917957d6554Steve Block    _selectHighlightState: function(lineNumber, preConditionStringified)
2112bde8e466a4451c7319e3a072d118917957d6554Steve Block    {
2122bde8e466a4451c7319e3a072d118917957d6554Steve Block        var state = this._textModel.getAttribute(lineNumber, "highlight");
2132bde8e466a4451c7319e3a072d118917957d6554Steve Block        if (state && state.preConditionStringified === preConditionStringified)
2142bde8e466a4451c7319e3a072d118917957d6554Steve Block            return state;
2152bde8e466a4451c7319e3a072d118917957d6554Steve Block
2162bde8e466a4451c7319e3a072d118917957d6554Steve Block        var outdatedState = this._textModel.getAttribute(lineNumber, "highlight-outdated");
2172bde8e466a4451c7319e3a072d118917957d6554Steve Block        if (outdatedState && outdatedState.preConditionStringified === preConditionStringified) {
2182bde8e466a4451c7319e3a072d118917957d6554Steve Block            // Swap states.
2192bde8e466a4451c7319e3a072d118917957d6554Steve Block            this._textModel.setAttribute(lineNumber, "highlight", outdatedState);
2202bde8e466a4451c7319e3a072d118917957d6554Steve Block            this._textModel.setAttribute(lineNumber, "highlight-outdated", state);
2212bde8e466a4451c7319e3a072d118917957d6554Steve Block            return outdatedState;
2222bde8e466a4451c7319e3a072d118917957d6554Steve Block        }
2232bde8e466a4451c7319e3a072d118917957d6554Steve Block
2242bde8e466a4451c7319e3a072d118917957d6554Steve Block        if (state)
2252bde8e466a4451c7319e3a072d118917957d6554Steve Block            this._textModel.setAttribute(lineNumber, "highlight-outdated", state);
2262bde8e466a4451c7319e3a072d118917957d6554Steve Block
2272bde8e466a4451c7319e3a072d118917957d6554Steve Block        state = {};
2282bde8e466a4451c7319e3a072d118917957d6554Steve Block        state.preConditionStringified = preConditionStringified;
2292bde8e466a4451c7319e3a072d118917957d6554Steve Block        this._textModel.setAttribute(lineNumber, "highlight", state);
2302bde8e466a4451c7319e3a072d118917957d6554Steve Block        return state;
2312bde8e466a4451c7319e3a072d118917957d6554Steve Block    },
2322bde8e466a4451c7319e3a072d118917957d6554Steve Block
2332bde8e466a4451c7319e3a072d118917957d6554Steve Block    _clearHighlightState: function(lineNumber)
2342bde8e466a4451c7319e3a072d118917957d6554Steve Block    {
2352bde8e466a4451c7319e3a072d118917957d6554Steve Block        this._textModel.removeAttribute(lineNumber, "highlight");
2362bde8e466a4451c7319e3a072d118917957d6554Steve Block        this._textModel.removeAttribute(lineNumber, "highlight-outdated");
237d0825bca7fe65beaee391d30da42e937db621564Steve Block    }
238d0825bca7fe65beaee391d30da42e937db621564Steve Block}
239