Skip to content
This repository was archived by the owner on Sep 6, 2021. It is now read-only.

Commit 04bcf56

Browse files
committed
Merge pull request #1753 from adobe/nj/factor-token-utils
Factor out generic token-navigation routines from HTMLUtils
2 parents 943433f + 0285579 commit 04bcf56

2 files changed

Lines changed: 144 additions & 105 deletions

File tree

src/language/HTMLUtils.js

Lines changed: 16 additions & 105 deletions
Original file line numberDiff line numberDiff line change
@@ -28,102 +28,13 @@
2828
define(function (require, exports, module) {
2929
"use strict";
3030

31+
var TokenUtils = require("utils/TokenUtils");
32+
3133
//constants
3234
var TAG_NAME = "tagName",
3335
ATTR_NAME = "attr.name",
3436
ATTR_VALUE = "attr.value";
3537

36-
/**
37-
* @private
38-
* moves the current context backwards by one token
39-
* @param {editor:{CodeMirror}, pos:{ch:{string}, line:{number}}, token:{object}} ctx
40-
* @return {boolean} whether the context changed
41-
*/
42-
function _movePrevToken(ctx) {
43-
if (ctx.pos.ch <= 0 || ctx.token.start <= 0) {
44-
//move up a line
45-
if (ctx.pos.line <= 0) {
46-
return false; //at the top already
47-
}
48-
ctx.pos.line--;
49-
ctx.pos.ch = ctx.editor.getLine(ctx.pos.line).length;
50-
} else {
51-
ctx.pos.ch = ctx.token.start;
52-
}
53-
ctx.token = ctx.editor.getTokenAt(ctx.pos);
54-
return true;
55-
}
56-
57-
/**
58-
* @private
59-
* moves the current context forward by one token
60-
* @param {editor:{CodeMirror}, pos:{ch:{string}, line:{number}}, token:{object}} ctx
61-
* @return {boolean} whether the context changed
62-
*/
63-
function _moveNextToken(ctx) {
64-
var eol = ctx.editor.getLine(ctx.pos.line).length;
65-
if (ctx.pos.ch >= eol || ctx.token.end >= eol) {
66-
//move down a line
67-
if (ctx.pos.line >= ctx.editor.lineCount() - 1) {
68-
return false; //at the bottom
69-
}
70-
ctx.pos.line++;
71-
ctx.pos.ch = 0;
72-
} else {
73-
ctx.pos.ch = ctx.token.end + 1;
74-
}
75-
ctx.token = ctx.editor.getTokenAt(ctx.pos);
76-
return true;
77-
}
78-
79-
/**
80-
* @private
81-
* moves the current context in the given direction, skipping any whitespace it hits
82-
* @param {function} moveFxn the funciton to move the context
83-
* @param {editor:{CodeMirror}, pos:{ch:{string}, line:{number}}, token:{object}} ctx
84-
* @return {boolean} whether the context changed
85-
*/
86-
function _moveSkippingWhitespace(moveFxn, ctx) {
87-
if (!moveFxn(ctx)) {
88-
return false;
89-
}
90-
while (!ctx.token.className && ctx.token.string.trim().length === 0) {
91-
if (!moveFxn(ctx)) {
92-
return false;
93-
}
94-
}
95-
return true;
96-
}
97-
98-
/**
99-
* @private
100-
* creates a context object
101-
* @param {CodeMirror} editor
102-
* @param {{ch:{string}, line:{number}} pos
103-
* @return {editor:{CodeMirror}, pos:{ch:{string}, line:{number}}, token:{object}}
104-
*/
105-
function _getInitialContext(editor, pos) {
106-
return {
107-
"editor": editor,
108-
"pos": pos,
109-
"token": editor.getTokenAt(pos)
110-
};
111-
}
112-
113-
/**
114-
* @private
115-
* in the given context, get the character offset of pos from the start of the token
116-
* @param {editor:{CodeMirror}, pos:{ch:{string}, line:{number}}, token:{object}} context
117-
* @return {number}
118-
*/
119-
function _offsetInToken(ctx) {
120-
var offset = ctx.pos.ch - ctx.token.start;
121-
if (offset < 0) {
122-
console.log("CodeHintUtils: _offsetInToken - Invalid context: the pos what not in the current token!");
123-
}
124-
return offset;
125-
}
126-
12738
/**
12839
* @private
12940
* Sometimes as attr values are getting typed, if the quotes aren't balanced yet
@@ -136,7 +47,7 @@ define(function (require, exports, module) {
13647
var attrValue = ctx.token.string,
13748
startChar = attrValue.charAt(0),
13849
endChar = attrValue.charAt(attrValue.length - 1),
139-
offset = _offsetInToken(ctx),
50+
offset = TokenUtils.offsetInToken(ctx),
14051
foundEqualSign = false;
14152

14253
//If this is a fully quoted value, return the whole
@@ -251,12 +162,12 @@ define(function (require, exports, module) {
251162
}
252163

253164
//Move to the prev token, and check if it's "="
254-
if (!_moveSkippingWhitespace(_movePrevToken, ctx) || ctx.token.string !== "=") {
165+
if (!TokenUtils.moveSkippingWhitespace(TokenUtils.movePrevToken, ctx) || ctx.token.string !== "=") {
255166
return createTagInfo();
256167
}
257168

258169
//Move to the prev token, and check if it's an attribute
259-
if (!_moveSkippingWhitespace(_movePrevToken, ctx) || ctx.token.className !== "attribute") {
170+
if (!TokenUtils.moveSkippingWhitespace(TokenUtils.movePrevToken, ctx) || ctx.token.className !== "attribute") {
260171
return createTagInfo();
261172
}
262173

@@ -283,13 +194,13 @@ define(function (require, exports, module) {
283194

284195
var tagName = _extractTagName(ctx);
285196
var attrName = ctx.token.string;
286-
var offset = _offsetInToken(ctx);
197+
var offset = TokenUtils.offsetInToken(ctx);
287198

288-
if (!_moveSkippingWhitespace(_moveNextToken, ctx) || ctx.token.string !== "=") {
199+
if (!TokenUtils.moveSkippingWhitespace(TokenUtils.moveNextToken, ctx) || ctx.token.string !== "=") {
289200
return createTagInfo(ATTR_NAME, offset, tagName, attrName);
290201
}
291202

292-
if (!_moveSkippingWhitespace(_moveNextToken, ctx)) {
203+
if (!TokenUtils.moveSkippingWhitespace(TokenUtils.moveNextToken, ctx)) {
293204
return createTagInfo(ATTR_NAME, offset, tagName, attrName);
294205
}
295206
//this should be the attrvalue
@@ -320,9 +231,9 @@ define(function (require, exports, module) {
320231
// the pos the caller passed in so we use extend to make a safe copy of it.
321232
// This is what pass by value in c++ would do.
322233
var pos = $.extend({}, constPos),
323-
ctx = _getInitialContext(editor._codeMirror, pos),
234+
ctx = TokenUtils.getInitialContext(editor._codeMirror, pos),
324235
tempCtx = null,
325-
offset = _offsetInToken(ctx),
236+
offset = TokenUtils.offsetInToken(ctx),
326237
tagInfo,
327238
tokenType;
328239

@@ -366,15 +277,15 @@ define(function (require, exports, module) {
366277
// use it to scan backwards if we don't find an equal sign here.
367278
// Comment out this block to fix issue #1510.
368279
// if (testToken.string.length > 0 && testToken.string.charAt(0) !== ">") {
369-
// tempCtx = _getInitialContext(editor._codeMirror, pos);
370-
// if (_moveSkippingWhitespace(_moveNextToken, tempCtx) && tempCtx.token.string === "=") {
280+
// tempCtx = TokenUtils.getInitialContext(editor._codeMirror, pos);
281+
// if (TokenUtils.moveSkippingWhitespace(TokenUtils.moveNextToken, tempCtx) && tempCtx.token.string === "=") {
371282
// // Return an empty tag info since we're between an atribute name and the equal sign.
372283
// return createTagInfo();
373284
// }
374285
// }
375286

376287
// next, see what's before pos
377-
if (!_movePrevToken(ctx)) {
288+
if (!TokenUtils.movePrevToken(ctx)) {
378289
return createTagInfo();
379290
}
380291

@@ -438,7 +349,7 @@ define(function (require, exports, module) {
438349
if (ctx.token.string === "=") {
439350
// We could be between the attr and the value
440351
// Step back and check
441-
if (!_moveSkippingWhitespace(_movePrevToken, ctx) || ctx.token.className !== "attribute") {
352+
if (!TokenUtils.moveSkippingWhitespace(TokenUtils.movePrevToken, ctx) || ctx.token.className !== "attribute") {
442353
return createTagInfo();
443354
}
444355

@@ -484,13 +395,13 @@ define(function (require, exports, module) {
484395
*/
485396
function findStyleBlocks(editor) {
486397
// Start scanning from beginning of file
487-
var ctx = _getInitialContext(editor._codeMirror, {line: 0, ch: 0});
398+
var ctx = TokenUtils.getInitialContext(editor._codeMirror, {line: 0, ch: 0});
488399

489400
var styleBlocks = [];
490401
var currentStyleBlock = null;
491402
var inStyleBlock = false;
492403

493-
while (_moveNextToken(ctx)) {
404+
while (TokenUtils.moveNextToken(ctx)) {
494405
if (inStyleBlock) {
495406
// Check for end of this <style> block
496407
if (ctx.token.state.mode !== "css") {

src/utils/TokenUtils.js

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
/*
2+
* Copyright (c) 2012 Adobe Systems Incorporated. All rights reserved.
3+
*
4+
* Permission is hereby granted, free of charge, to any person obtaining a
5+
* copy of this software and associated documentation files (the "Software"),
6+
* to deal in the Software without restriction, including without limitation
7+
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
8+
* and/or sell copies of the Software, and to permit persons to whom the
9+
* Software is furnished to do so, subject to the following conditions:
10+
*
11+
* The above copyright notice and this permission notice shall be included in
12+
* all copies or substantial portions of the Software.
13+
*
14+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19+
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20+
* DEALINGS IN THE SOFTWARE.
21+
*
22+
*/
23+
24+
25+
/*jslint vars: true, plusplus: true, devel: true, nomen: true, indent: 4, maxerr: 50 */
26+
/*global define, $ */
27+
28+
/**
29+
* Functions for iterating through tokens in the current editor buffer. Useful for doing
30+
* light parsing that can rely purely on information gathered by the code coloring mechanism.
31+
*/
32+
33+
define(function (require, exports, module) {
34+
"use strict";
35+
36+
/**
37+
* Creates a context object for the given editor and position, suitable for passing to the
38+
* move functions.
39+
* @param {CodeMirror} editor
40+
* @param {{ch:{string}, line:{number}} pos
41+
* @return {editor:{CodeMirror}, pos:{ch:{string}, line:{number}}, token:{object}}
42+
*/
43+
function getInitialContext(editor, pos) {
44+
return {
45+
"editor": editor,
46+
"pos": pos,
47+
"token": editor.getTokenAt(pos)
48+
};
49+
}
50+
51+
/**
52+
* Moves the given context backwards by one token.
53+
* @param {editor:{CodeMirror}, pos:{ch:{string}, line:{number}}, token:{object}} ctx
54+
* @return {boolean} whether the context changed
55+
*/
56+
function movePrevToken(ctx) {
57+
if (ctx.pos.ch <= 0 || ctx.token.start <= 0) {
58+
//move up a line
59+
if (ctx.pos.line <= 0) {
60+
return false; //at the top already
61+
}
62+
ctx.pos.line--;
63+
ctx.pos.ch = ctx.editor.getLine(ctx.pos.line).length;
64+
} else {
65+
ctx.pos.ch = ctx.token.start;
66+
}
67+
ctx.token = ctx.editor.getTokenAt(ctx.pos);
68+
return true;
69+
}
70+
71+
/**
72+
* Moves the given context forward by one token.
73+
* @param {editor:{CodeMirror}, pos:{ch:{string}, line:{number}}, token:{object}} ctx
74+
* @return {boolean} whether the context changed
75+
*/
76+
function moveNextToken(ctx) {
77+
var eol = ctx.editor.getLine(ctx.pos.line).length;
78+
if (ctx.pos.ch >= eol || ctx.token.end >= eol) {
79+
//move down a line
80+
if (ctx.pos.line >= ctx.editor.lineCount() - 1) {
81+
return false; //at the bottom
82+
}
83+
ctx.pos.line++;
84+
ctx.pos.ch = 0;
85+
} else {
86+
ctx.pos.ch = ctx.token.end + 1;
87+
}
88+
ctx.token = ctx.editor.getTokenAt(ctx.pos);
89+
return true;
90+
}
91+
92+
/**
93+
* Moves the given context in the given direction, skipping any whitespace it hits.
94+
* @param {function} moveFxn the funciton to move the context
95+
* @param {editor:{CodeMirror}, pos:{ch:{string}, line:{number}}, token:{object}} ctx
96+
* @return {boolean} whether the context changed
97+
*/
98+
function moveSkippingWhitespace(moveFxn, ctx) {
99+
if (!moveFxn(ctx)) {
100+
return false;
101+
}
102+
while (!ctx.token.className && ctx.token.string.trim().length === 0) {
103+
if (!moveFxn(ctx)) {
104+
return false;
105+
}
106+
}
107+
return true;
108+
}
109+
110+
/**
111+
* In the given context, get the character offset of pos from the start of the token.
112+
* @param {editor:{CodeMirror}, pos:{ch:{string}, line:{number}}, token:{object}} context
113+
* @return {number}
114+
*/
115+
function offsetInToken(ctx) {
116+
var offset = ctx.pos.ch - ctx.token.start;
117+
if (offset < 0) {
118+
console.log("CodeHintUtils: _offsetInToken - Invalid context: the pos what not in the current token!");
119+
}
120+
return offset;
121+
}
122+
123+
exports.movePrevToken = movePrevToken;
124+
exports.moveNextToken = moveNextToken;
125+
exports.moveSkippingWhitespace = moveSkippingWhitespace;
126+
exports.getInitialContext = getInitialContext;
127+
exports.offsetInToken = offsetInToken;
128+
});

0 commit comments

Comments
 (0)