From 98e2821b38a775737e42a2479a6bc65107210859 Mon Sep 17 00:00:00 2001 From: Elliot Kroo Date: Thu, 11 Mar 2010 15:21:30 -0800 Subject: reorganizing the first level of folders (trunk/branch folders are not the git way :) --- infrastructure/ace/www/multilang_lexer.js | 349 ++++++++++++++++++++++++++++++ 1 file changed, 349 insertions(+) create mode 100644 infrastructure/ace/www/multilang_lexer.js (limited to 'infrastructure/ace/www/multilang_lexer.js') diff --git a/infrastructure/ace/www/multilang_lexer.js b/infrastructure/ace/www/multilang_lexer.js new file mode 100644 index 0000000..9617981 --- /dev/null +++ b/infrastructure/ace/www/multilang_lexer.js @@ -0,0 +1,349 @@ +/** + * Copyright 2009 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS-IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +AceLexer = (function lexer_init() { + +function makeIncrementalLexer(lineParser) { + + var parseLine = lineParser.parseLine; + var initialState = lineParser.initialState; + var getClassesForScope = lineParser.getClassesForScope; + + var lineData = newSkipList(); // one entry per line + var buffer = ""; // full text of document, each line ending with \n + var lineStatus = ""; // one char per line in buffer, (d)irty/(u)ncolored/(c)olored + var nextLineDataId = 1; + + // "dirty" lines are unparsed lines. Other lines have properties startState,endState. + // "uncolored" lines are parsed but the data has not been handled by ACE. + + function roundBackToLineIndex(charOffset) { // charOffset is [0,document length] + return lineData.indexOfOffset(charOffset); + // result is [0,num lines] + } + + function roundForwardToLineIndex(charOffset) { // charOffset is [0,document length] + var idx = lineData.indexOfOffset(charOffset); + var newCharOffset = lineData.offsetOfIndex(idx); + if (newCharOffset < charOffset) { + // rounded back, round forward instead + return idx + 1; + } + return idx; + // result is [0,num lines] + } + + function updateBuffer(newBuffer, spliceStart, charsRemoved, charsAdded) { + // newBuffer is string to replace buffer, other args explain the splice + // that happened between the old buffer and newBuffer + + // determine range of lines (and character offsets of line boundaries) affected + var spliceStartLineIndex = roundBackToLineIndex(spliceStart); + var spliceStartCharOffset = lineData.offsetOfIndex(spliceStartLineIndex); + var spliceEndLineIndex = roundForwardToLineIndex(spliceStart + charsRemoved); + var spliceEndCharOffset = lineData.offsetOfIndex(spliceEndLineIndex); + + var extraBeginChars = spliceStart - spliceStartCharOffset; + var extraEndChars = spliceEndCharOffset - (spliceStart + charsRemoved); + var newChars = newBuffer.substring(spliceStart - extraBeginChars, + spliceStart + charsAdded + extraEndChars); + + var newLineEntries = []; + newChars.replace(/[^\n]*\n/g, function(line) { + newLineEntries.push({ width: line.length, key: String(nextLineDataId++) }); + }); + + lineData.splice(spliceStartLineIndex, spliceEndLineIndex - spliceStartLineIndex, + newLineEntries); + + var newDirtyStatus = ""; + for(var i=0;i spliceStartLineIndex) { + // pure deletion of one or more lines, mark the next line after + // the deletion as dirty to trigger relexing + newDirtyStatus = "d"; + extraDirty = 1; + } + lineStatus = lineStatus.substring(0, spliceStartLineIndex) + + newDirtyStatus + lineStatus.substring(spliceEndLineIndex + extraDirty); + + buffer = newBuffer; + } + + function findBeginningOfDirtyRegion(dirtyLineIndex) { + // search backwards for a line that is either the first line + // or is preceded by a non-dirty line. + var cleanLine = Math.max(lineStatus.lastIndexOf("c", dirtyLineIndex), + lineStatus.lastIndexOf("u", dirtyLineIndex)); + // cleanLine is now either -1 (if all lines are dirty back to beginning of doc) + // or the index of a clean line + return cleanLine + 1; + } + + function findEndOfUncoloredRegion(uncoloredLineIndex) { + // search forwards for a line that is not uncolored, + // or return number of lines in doc if end of doc is hit. + var idx1 = lineStatus.indexOf("c", uncoloredLineIndex); + var idx2 = lineStatus.indexOf("d", uncoloredLineIndex); + if (idx1 < 0) { + if (idx2 < 0) return lineStatus.length; + else return idx2; + } + else { + if (idx2 < 0) return idx1; + else return Math.min(idx1, idx2); + } + } + + function getLineText(lineIndex) { + var lineEntry = lineData.atIndex(lineIndex); + var lineTextStart = lineData.offsetOfIndex(lineIndex); + var lineTextEnd = lineTextStart + lineEntry.width; + return buffer.substring(lineTextStart, lineTextEnd); + } + + function setLineStatus(lineIndex, status) { + lineStatus = lineStatus.substring(0, lineIndex) + status + + lineStatus.substring(lineIndex+1); + } + + function lexCharRange(charRange, isTimeUp) { + if (isTimeUp()) return; + + var lexStart = roundBackToLineIndex(charRange[0]); + var lexEnd = roundForwardToLineIndex(charRange[1]); + + // can't parse a dirty line in the middle of a dirty region, + // no sensible start state; so find beginning of dirty region + var nextCandidate = findBeginningOfDirtyRegion(lexStart); + + while (! isTimeUp()) { + // find a dirty line to parse; if may be before lexStart, + // but stop at lexEnd. + var nextDirty = lineStatus.indexOf("d", nextCandidate); + if (nextDirty < 0 || nextDirty >= lexEnd) { + break; + } + var theLineIndex = nextDirty; + var theLineEntry = lineData.atIndex(theLineIndex); + var lineText = getLineText(theLineIndex); + + // assert: previous line is not dirty + var startState; + if (theLineIndex > 0) { + startState = lineData.atIndex(theLineIndex-1).endState; + } + else { + startState = initialState; + } + + var tokenWidths = []; + var tokenNames = []; + var tokenFunc = function(str, cls) { + tokenWidths.push(str.length); + tokenNames.push(cls); + } + var endState = parseLine(lineText, startState, tokenFunc); + + theLineEntry.startState = startState; + theLineEntry.endState = endState; + theLineEntry.tokenWidths = tokenWidths; + theLineEntry.tokenNames = tokenNames; + + setLineStatus(theLineIndex, "u"); + + nextCandidate = theLineIndex + 1; + if (nextCandidate < lineStatus.length && + lineStatus.charAt(nextCandidate) != "d" && + lineData.atIndex(nextCandidate).startState != endState) { + // state has changed, lexing must continue past end of dirty + // region + setLineStatus(nextCandidate, "d"); + } + } + } + + function forEachUncoloredSubrange(startChar, endChar, func, isTimeUp) { + var startLine = roundBackToLineIndex(startChar); + var endLine = roundForwardToLineIndex(endChar); + + var nextCandidate = startLine; + + while (! isTimeUp()) { + var nextUncolored = lineStatus.indexOf("u", nextCandidate); + if (nextUncolored < 0 || nextUncolored >= endLine) { + break; + } + var uncoloredEndLine = findEndOfUncoloredRegion(nextUncolored); + + var rangeStart = Math.max(startChar, lineData.offsetOfIndex(nextUncolored)); + var rangeEnd = Math.min(endChar, lineData.offsetOfIndex(uncoloredEndLine)); + + func(rangeStart, rangeEnd, isTimeUp); + + nextCandidate = uncoloredEndLine; + } + } + + function getSpansForRange(startChar, endChar, func, justPeek) { + var startLine = roundBackToLineIndex(startChar); + var endLine = roundForwardToLineIndex(endChar); + + function doToken(tokenStart, tokenWidth, tokenClass) { + // crop token to [startChar,endChar] range + if (tokenStart + tokenWidth <= startChar) return; + if (tokenStart >= endChar) return; + if (tokenStart < startChar) { + tokenWidth -= (startChar - tokenStart); + tokenStart = startChar; + } + if (tokenStart + tokenWidth > endChar) { + tokenWidth -= (tokenStart + tokenWidth - endChar); + } + if (tokenWidth <= 0) return; + func(tokenWidth, tokenClass); + } + + for(var i=startLine; i'); + else html.push(''); + html.push(escapeHTML(txt),''); + atLineStart = false; + } + function newLineFunc() { + html.push('
\n'); + atLineStart = true; + } + simpleLexer.lexAsLines(codeString, tokenFunc, newLineFunc); + if (atLineStart) html.push('
\n'); + return html.join(''); +} + +function escapeHTML(s) { + var re = /[&<>\'\" ]/g; + if (! re.MAP) { + // persisted across function calls! + re.MAP = { + '&': '&', + '<': '<', + '>': '>', + '"': '"', + "'": ''', + ' ': ' ' + }; + } + return s.replace(re, function(c) { return re.MAP[c]; }); +} + +function getIncrementalLexer(type) { + return makeIncrementalLexer(grammars["text.html.basic"]);//grammars[type]); +} +function getSimpleLexer(type) { + return makeSimpleLexer(grammars[type]); +} + +return {getIncrementalLexer:getIncrementalLexer, getSimpleLexer:getSimpleLexer, + codeStringToHTML:codeStringToHTML}; + +})(); -- cgit v1.2.3-1-g7c22