toggle comment support

This commit is contained in:
Vadim Lopatin 2015-02-09 15:28:54 +03:00
parent da9eafebaf
commit 4000298679
3 changed files with 112 additions and 5 deletions

View File

@ -89,7 +89,7 @@ class ArraySourceLines : SourceLines {
/// source file
override @property SourceFile file() { return _file; }
/// last read line
override @property uint line() { return _line; }
override @property uint line() { return _line + _firstLine; }
/// source encoding
//@property EncodingType encoding() { return _encoding; }
/// error code

View File

@ -928,6 +928,8 @@ class Token {
@property Keyword keyword() { return Keyword.NONE; }
/// returns true if this is documentation comment token
@property bool isDocumentationComment() { return false; }
/// returns true if this is multiline
@property bool isMultilineComment() { return false; }
// error handling
@ -1024,7 +1026,9 @@ class OpToken : Token {
super(TokenType.OP, file, line, pos);
}
override public Token clone() {
return new OpToken(_file, _line, _pos);
OpToken res = new OpToken(_file, _line, _pos);
res._op = _op;
return res;
}
public override @property string toString() {
return "Op:" ~ to!string(_op);
@ -1043,7 +1047,9 @@ class KeywordToken : Token {
super(TokenType.KEYWORD, file, line, pos);
}
override public Token clone() {
return new KeywordToken(_file, _line, _pos);
KeywordToken res = new KeywordToken(_file, _line, _pos);
res._keyword = _keyword;
return res;
}
public override @property string toString() {
return "Keyword:" ~ to!string(_keyword);
@ -1054,6 +1060,8 @@ class KeywordToken : Token {
class CommentToken : Token {
protected dchar[] _text;
protected bool _isDocumentationComment;
protected bool _isMultilineComment;
override @property bool isDocumentationComment() {
return _isDocumentationComment;
@ -1063,6 +1071,15 @@ class CommentToken : Token {
_isDocumentationComment = f;
}
/// returns true if this is multiline
override @property bool isMultilineComment() {
return _isMultilineComment;
}
@property void isMultilineComment(bool f) {
_isMultilineComment = f;
}
@property override dchar[] text() { return _text; }
@property void text(dchar[] text) { _text = text; }
this() {
@ -1073,7 +1090,10 @@ class CommentToken : Token {
_text = text;
}
override public Token clone() {
return new CommentToken(_file, _line, _pos, _text.dup);
CommentToken res = new CommentToken(_file, _line, _pos, _text.dup);
res._isDocumentationComment = _isDocumentationComment;
res._isMultilineComment = _isMultilineComment;
return res;
}
public override @property string toString() {
return "Comment:" ~ to!string(_text);
@ -1413,7 +1433,7 @@ class Tokenizer
init(lineStream);
}
void init(SourceLines lineStream) {
void init(SourceLines lineStream, int pos = 0) {
_lineStream = lineStream;
SourceFile file = _lineStream.file;
_sharedWhiteSpaceToken.setFile(file);
@ -1432,6 +1452,7 @@ class Tokenizer
_prevLineLength = 0;
_lineText = null;
nextLine();
_pos = pos;
}
this(string code, string filename = "") {
@ -1532,6 +1553,7 @@ class Tokenizer
protected Token processMultilineComment() {
_sharedCommentToken.setPos(_line, _pos - 1);
_sharedCommentToken.isDocumentationComment = _pos + 1 < _lineText.length && _lineText[_pos + 1] == '*';
_sharedCommentToken.isMultilineComment = true;
_commentAppender.reset();
int textStart = _pos + 1;
for (;;) {
@ -1566,6 +1588,7 @@ class Tokenizer
protected Token processNestedComment() {
_sharedCommentToken.setPos(_line, _pos - 1);
_sharedCommentToken.isDocumentationComment = _pos + 1 < _lineText.length && _lineText[_pos + 1] == '+';
_sharedCommentToken.isMultilineComment = true;
_commentAppender.reset();
dchar[] text;
int textStart = _pos + 1;

View File

@ -119,6 +119,9 @@ class SimpleDSyntaxHighlighter : SyntaxHighlighter {
/// return true if can toggle line comments for specified text range
override bool canToggleLineComment(TextRange range) {
TextRange r = content.fullLinesRange(range);
if (isInsideBlockComment(r.start) || isInsideBlockComment(r.end))
return false;
return true;
}
@ -176,9 +179,90 @@ class SimpleDSyntaxHighlighter : SyntaxHighlighter {
return cast(dstring)res;
}
/// searches for neares token start before or equal to position
protected TextPosition tokenStart(TextPosition pos) {
TextPosition p = pos;
for (;;) {
TextPosition prevPos = content.prevCharPos(p);
if (p == prevPos)
return p; // begin of file
TokenProp prop = content.tokenProp(p);
TokenProp prevProp = content.tokenProp(prevPos);
if (prop && prop != prevProp)
return p;
p = prevPos;
}
}
static struct TokenWithRange {
Token token;
TextRange range;
@property string toString() {
return token.toString ~ range.toString;
}
}
protected TextPosition _lastTokenStart;
protected Token _lastToken;
protected bool initTokenizer(TextPosition startPos) {
const dstring[] lines = content.lines;
_lines.init(cast(dstring[])(lines[startPos.line .. $]), _file, startPos.line);
_tokenizer.init(_lines, startPos.pos);
_lastTokenStart = startPos;
_lastToken = null;
nextToken();
return true;
}
protected TokenWithRange nextToken() {
TokenWithRange res;
if (_lastToken && _lastToken.type == TokenType.EOF) {
// end of file
res.range.start = _lastTokenStart;
res.range.end = content.endOfFile();
res.token = null;
return res;
}
res.range.start = _lastTokenStart;
res.token = _lastToken;
_lastToken = _tokenizer.nextToken();
if (_lastToken)
_lastToken = _lastToken.clone();
_lastTokenStart = _lastToken ? TextPosition(_lastToken.line - 1, _lastToken.pos - 1) : content.endOfFile();
res.range.end = _lastTokenStart;
return res;
}
protected TokenWithRange getPositionToken(TextPosition pos) {
Log.d("getPositionToken for ", pos);
TextPosition start = tokenStart(pos);
Log.d("token start found: ", start);
initTokenizer(start);
for (;;) {
TokenWithRange tokenRange = nextToken();
Log.d("read token: ", tokenRange);
if (!tokenRange.token) {
Log.d("end of file");
return tokenRange;
}
if (pos >= tokenRange.range.start && pos < tokenRange.range.end) {
Log.d("found: ", pos, " in ", tokenRange);
return tokenRange;
}
}
}
protected bool isInsideBlockComment(TextPosition pos) {
TokenWithRange tokenRange = getPositionToken(pos);
if (tokenRange.token && tokenRange.token.type == TokenType.COMMENT && tokenRange.token.isMultilineComment)
return pos > tokenRange.range.start && pos < tokenRange.range.end;
return false;
}
/// toggle line comments for specified text range
override void toggleLineComment(TextRange range, Object source) {
TextRange r = content.fullLinesRange(range);
if (isInsideBlockComment(r.start) || isInsideBlockComment(r.end))
return;
int lineCount = r.end.line - r.start.line;
bool noEolAtEndOfRange = false;
if (lineCount == 0 || r.end.pos > 0) {