CodeEditorTagIdent.diff

Production version with IdentRecognizer - Zbigniew Rebacz, 02/20/2016 11:44 PM

Download (15.3 KB)

View differences:

CodeEditor.h (kopia robocza)
141 141
	virtual ~EditorBar();
142 142
};
143 143

  
144
// TODO: When C++11 will be avaliable in CodeEditor class replace with enum class
145
// Current version is not typed safe!!!
146
enum IdentType {
147
	IDENT_TYPE_SPACE = 0,
148
	IDENT_TYPE_TAB,
149
	IDENT_TYPE_UNKNOWN
150
};
151

  
152
class IdentRecognizer {
153
public:
154
	IdentRecognizer(CodeEditor *editor, int spaceIdentDefaultSize = 4);
155
	virtual ~IdentRecognizer();
156
	
157
	IdentType FindIdentType();
158
	IdentType FindIdentType(const WString& line);
159
	int       FindIdentLevel(const WString& line, IdentType type);
160
	
161
	int    GetSpaceIdentDefaultSize() const;
162
	char   GetIdentChar(IdentType type);
163
	String GetIdentString(IdentType type, int identLevel = 1);
164
	int    GetIdentCharCount(IdentType type, int identLevel = 1);
165
	
166
	void SetSpaceIdentDefaultSize(int spaceIdentDefaultSize);
167
	
168
private:
169
	IdentType FindIdentTypeInLine(const WString& line);
170
	int       FindSpaceIdentSize();
171
	
172
private:
173
	CodeEditor* editor;
174
	int         spaceIdentDefaultSize;
175
};
176

  
144 177
struct IdentPos {
145 178
	int    begin;
146 179
	int    end;
CodeEditor.upp (kopia robocza)
29 29
	TagSyntax.h,
30 30
	TagSyntax.cpp,
31 31
	PythonSyntax readonly separator,
32
	PythonSyntax.h,
32 33
	PythonSyntax.cpp,
33
	PythonSyntax.h,
34 34
	LogSyntax readonly separator,
35 35
	LogSyntax.h,
36 36
	LogSyntax.cpp,
......
38 38
	EditorBar.cpp,
39 39
	FindReplace.cpp,
40 40
	Lang.cpp,
41
	IndentRecognizer.cpp,
41 42
	CodeEditor.cpp,
42 43
	CodeEditor.lay,
43 44
	CodeEditor.iml,
IndentRecognizer.cpp (kopia robocza)
1
#include "CodeEditor.h"
2

  
3
NAMESPACE_UPP
4

  
5
IdentRecognizer::IdentRecognizer(CodeEditor *editor, int spaceIdentDefaultSize)
6
{
7
	this->editor = editor;
8
	this->spaceIdentDefaultSize = spaceIdentDefaultSize;
9
}
10

  
11
IdentRecognizer::~IdentRecognizer() {}
12

  
13
int IdentRecognizer::FindIdentLevel(const WString& line, IdentType type)
14
{
15
	int level = 0;
16
	for(int i = 0; i < line.GetLength(); i++) {
17
		if(type == IDENT_TYPE_TAB && line[i] == '\t')
18
			level++;
19
		else
20
		if(type == IDENT_TYPE_SPACE && line[i] == ' ')
21
			level++;
22
		else
23
			break;
24
	}
25
	
26
	if (type == IDENT_TYPE_SPACE)
27
		level /= FindSpaceIdentSize();
28
	
29
	return level;
30
}
31

  
32
IdentType IdentRecognizer::FindIdentType(const WString& line)
33
{
34
	IdentType type = FindIdentTypeInLine(line);
35
	if(type == IDENT_TYPE_UNKNOWN)
36
		type = FindIdentType();
37
	return type;
38
}
39

  
40
IdentType IdentRecognizer::FindIdentType()
41
{
42
	IdentType type = IDENT_TYPE_UNKNOWN;
43
	for(int i = 0; i < editor->GetLineCount(); i++) {
44
		IdentType ctype = FindIdentTypeInLine(editor->GetWLine(i));
45
		if(ctype != IDENT_TYPE_UNKNOWN) {
46
			type = ctype;
47
			break;
48
		}
49
	}
50
	return type;
51
}
52

  
53
int IdentRecognizer::GetSpaceIdentDefaultSize() const
54
{
55
	return spaceIdentDefaultSize;
56
}
57

  
58
char IdentRecognizer::GetIdentChar(IdentType type)
59
{
60
	if(type == IDENT_TYPE_SPACE)
61
		return ' ';
62
	return '\t';
63
}
64

  
65
String IdentRecognizer::GetIdentString(IdentType type, int identLevel)
66
{
67
	String ident, baseIdent;
68
	if(type == IDENT_TYPE_SPACE) {
69
		for(int i = 0; i < FindSpaceIdentSize(); i++)
70
			baseIdent += " ";
71
	}
72
	else
73
		baseIdent = "\t";
74
	
75
	for(int i = 0 ; i < identLevel; i++)
76
		ident += baseIdent;
77
	
78
	return ident;
79
}
80

  
81
int IdentRecognizer::GetIdentCharCount(IdentType type, int identLevel)
82
{
83
	return GetIdentString(type, identLevel).GetCount();
84
}
85

  
86
void IdentRecognizer::SetSpaceIdentDefaultSize(int spaceIdentDefaultSize)
87
{
88
	this->spaceIdentDefaultSize = spaceIdentDefaultSize;
89
}
90

  
91
IdentType IdentRecognizer::FindIdentTypeInLine(const WString& line)
92
{
93
	IdentType type = IDENT_TYPE_UNKNOWN;
94
	if(line.StartsWith("\t"))
95
		type = IDENT_TYPE_TAB;
96
	else
97
	if(line.StartsWith(" "))
98
		type = IDENT_TYPE_SPACE;
99
	return type;
100
}
101

  
102
int IdentRecognizer::FindSpaceIdentSize()
103
{
104
	int current = 0;
105
	for(int i = 0; i < editor->GetLineCount(); i++) {
106
		WString line = editor->GetWLine(i);
107
		bool hasNonSpaceEnd = false;
108
		for(int j = 0; j < line.GetLength(); j++) {
109
			if(line[j] == ' ')
110
				current++;
111
			else {
112
				hasNonSpaceEnd = true;
113
				break;
114
			}
115
		}
116
		
117
		if(!hasNonSpaceEnd) {
118
			current = 0;
119
			continue;
120
		}
121
		else
122
		if(current > 0)
123
			break;
124
	}
125
	
126
	return current > 0 ? current : spaceIdentDefaultSize;
127
}
128

  
129
END_UPP_NAMESPACE
PythonSyntax.cpp (kopia robocza)
68 68

  
69 69
void PythonSyntax::IndentInsert(CodeEditor& editor, int chr, int count)
70 70
{
71
	IdentRecognizer recognizer(&editor);
72
	
71 73
	if(chr == '\n') {
72 74
		while(count--) {
73
			WString cursorLine = editor.GetWLine(editor.GetCursorLine());
75
			WString line = editor.GetWLine(editor.GetCursorLine());
74 76
			editor.InsertChar('\n', 1);
75 77
			
76
			Identation::Type idType = FindIdentationType(editor, cursorLine);
77
			char idChar = GetIdentationByType(idType);
78
			int mult = 1;
79
			if(idType == Identation::Space)
80
				mult = CalculateSpaceIndetationSize(editor);
81
			if(LineHasColon(cursorLine))
82
				editor.InsertChar(idChar, mult);
83
			editor.InsertChar(idChar, CalculateLineIndetations(cursorLine, idType));
78
			IdentType identType = recognizer.FindIdentType(line);
79
			int level = recognizer.FindIdentLevel(line, identType);
80
			if(LineHasColon(line))
81
				level++;
82
			editor.InsertChar(recognizer.GetIdentChar(identType), recognizer.GetIdentCharCount(identType, level));
84 83
		}
85 84
	}
86 85
	if(count > 0)
......
142 141

  
143 142
bool PythonSyntax::LineHasColon(const WString& line)
144 143
{
144
	// TODO: Bugfix is needed - what about cursor is not at the end of line???
145 145
	for(int i = line.GetLength() - 1; i >= 0; i--) {
146 146
		if(line[i] == ':')
147 147
			return true;
......
149 149
	return false;
150 150
}
151 151

  
152
int PythonSyntax::CalculateLineIndetations(const WString& line, Identation::Type type)
153
{
154
	int count = 0;
155
	for(int i = 0; i < line.GetLength(); i++) {
156
		if(type == Identation::Tab && line[i] == '\t')
157
			count++;
158
		else
159
		if(type == Identation::Space && line[i] == ' ')
160
			count++;
161
		else
162
			break;
163
	}
164
	return count;
165
}
166

  
167
PythonSyntax::Identation::Type PythonSyntax::FindIdentationType(CodeEditor& editor, const WString& line)
168
{
169
	Identation::Type type = Identation::None;
170
	if(line.StartsWith("\t"))
171
		type = Identation::Tab;
172
	else
173
	if(line.StartsWith(" "))
174
		type = Identation::Space;
175
	else {
176
		for(int i = 0; i < editor.GetLineCount(); i++) {
177
			WString cLine = editor.GetWLine(i);
178
			if(cLine.StartsWith("\t")) {
179
				type = Identation::Tab;
180
				break;
181
			}
182
			else
183
			if(cLine.StartsWith(" ")) {
184
				type = Identation::Space;
185
				break;
186
			}
187
		}
188
	}
189
	return type;
190
}
191

  
192
int PythonSyntax::CalculateSpaceIndetationSize(CodeEditor& editor)
193
{
194
	int current = 0;
195
	for(int i = 0; i < editor.GetLineCount(); i++) {
196
		WString line = editor.GetWLine(i);
197
		for(int j = 0; j < line.GetLength(); j++) {
198
			if(line[j] == ' ')
199
				current++;
200
			else
201
				break;
202
		}
203
		
204
		if(current > 0)
205
			break;
206
	}
207
	
208
	// TODO: 4 is magic numer - try to find the way to get this number from ide constants
209
	return current > 0 ? current : 4;
210
}
211

  
212
char PythonSyntax::GetIdentationByType(Identation::Type type)
213
{
214
	if(type == Identation::Space)
215
		return ' ';
216
	return '\t';
217
}
218

  
219 152
END_UPP_NAMESPACE
PythonSyntax.h (kopia robocza)
1 1
class PythonSyntax : public EditorSyntax {
2
private:
3
	struct Identation {
4
		enum Type {
5
			Tab = 0,
6
			Space,
7
			None
8
		};
9
	};
10

  
11 2
public:
12 3
	PythonSyntax();
13 4

  
......
26 17
	void LoadSyntax(const char* keywordsArray[], const char* specialVarsArray[]);
27 18
	
28 19
	bool             LineHasColon(const WString& line);
29
	int              CalculateLineIndetations(const WString& line, Identation::Type type);
30
	int              CalculateSpaceIndetationSize(CodeEditor& editor);
31
	Identation::Type FindIdentationType(CodeEditor& editor, const WString& line);
32
	char             GetIdentationByType(Identation::Type type);
33 20
	
34 21
private:
35 22
	Index<String> keywords;
TagSyntax.cpp (kopia robocza)
8 8
	hout = NULL;
9 9
	html = true;
10 10
	witz = false;
11
	
12
	InitSpecialTags();
11 13
}
12 14

  
13 15
void TagSyntax::Clear()
......
278 280

  
279 281
void TagSyntax::IndentInsert(CodeEditor& editor, int chr, int count)
280 282
{
281
	if(status == SCRIPT)
283
	if(status == SCRIPT) {
282 284
		script.IndentInsert(editor, chr, count);
285
		return;
286
	}
287
	
288
	IdentRecognizer recognizer(&editor);
289
	if(chr == '\n') {
290
		while(count--) {
291
			WString line = editor.GetWLine(editor.GetCursorLine());
292
			IdentType identType = recognizer.FindIdentType(line);
293
			
294
			int currentLevel = recognizer.FindIdentLevel(line, identType);
295
			int newLevel = GetNewIdnetations(editor);
296
			int level = currentLevel + newLevel;
297
			
298
			String afterCursor;
299
			if(newLevel > 0) {
300
				WString rightSide = GetCursorLineRightSide(editor);
301
				if(rightSide.StartsWith("<")) {
302
					afterCursor = "\n";
303
					for(int i = 0; i < level - 1; i++)
304
						afterCursor += recognizer.GetIdentString(identType);
305
				}
306
				else
307
				if(!rightSide.IsEmpty())
308
					level = 0;
309
			}
310
			
311
			editor.InsertChar('\n', 1);
312
			editor.InsertChar(recognizer.GetIdentChar(identType), recognizer.GetIdentCharCount(identType, level));
313
			editor.Insert(editor.GetCursor(), afterCursor);
314
		}
315
	}
283 316
	else
317
	if(count > 0)
284 318
		editor.InsertChar(chr, count);
285 319
}
286 320

  
......
291 325
	return false;
292 326
}
293 327

  
328
bool TagSyntax::HasHtmlTags() const
329
{
330
	return html || witz;
331
}
332

  
333
int TagSyntax::GetIdentationsLevel(CodeEditor& editor) const
334
{
335
	int level = 0;
336
	WString line = editor.GetWLine(editor.GetCursorLine());
337
	for(int i = 0; i < line.GetCount(); i++) {
338
		if(line[i] == '\t')
339
			level++;
340
		else
341
			break;
342
	}
343
	return level;
344
}
345

  
346
int TagSyntax::GetNewIdnetations(CodeEditor& editor) const
347
{
348
	int level = 0;
349
	
350
	WString leftSide = GetCursorLineLeftSide(editor);
351
	WString rightSide = GetCursorLineRightSide(editor);
352
	Vector< Tuple2<String, int> > types = SplitTagsByType(leftSide);
353
	for(int i = 0; i < types.GetCount(); i++) {
354
		if(types[i].b == TAG)
355
			level++;
356
		else
357
		if(types[i].b == ENDTAG) {
358
			if(level > 0)
359
				level--;
360
		}
361
	}
362
	if(IsCursorInsideTag(leftSide, rightSide))
363
		level++;
364
	
365
	if(level < 0)
366
		level++;
367
	
368
	return level;
369
}
370

  
371
Vector< Tuple2<String, int> > TagSyntax::SplitTagsByType(const WString& s) const
372
{
373
	Vector< Tuple2<String, int> > tags;
374
	
375
	wchar  strc;
376
	bool   isStr = false;
377
	bool   isTag = false;
378
	int    type = TAG;
379
	String name;
380
	for(int i = 0; i < s.GetCount(); i++) {
381
		wchar c = s[i];
382
		
383
		if(c == '\'' || c == '\"') {
384
			if(!isStr) {
385
				isStr = true;
386
				strc = c;
387
			}
388
			else
389
			if(isStr && c == strc)
390
				isStr = false;
391
		}
392
		else
393
		if(c == '<') {
394
			isTag = true;
395
			if(i + 1 >= s.GetCount())
396
				continue;
397
			wchar nc = s[i + 1];
398
			if(nc == '/') {
399
				type = ENDTAG;
400
				i++;
401
			}
402
			else
403
			if(nc == '!' || nc == '?') {
404
				type = TAG0;
405
				i++;
406
			}
407
			i++;
408
			name = FindTagName(s, i);
409
		}
410
		else
411
		if(c == '>') {
412
			if(!isTag || i - 1 < 0)
413
				continue;
414
			
415
			wchar pc = s[i - 1];
416
			if(pc == '/' && type == TAG)
417
				type = TAG0;
418
			
419
			if(HasHtmlTags() && type != TAG0) {
420
				if(htmlSpecialTags.Find(name) > -1)
421
					type = TAG0;
422
			}
423
			
424
			tags.Add(Tuple<String, int>(name, type));
425
			type = TAG;
426
			isTag = false;
427
		}
428
	}
429
	
430
	return tags;
431
}
432

  
433
String TagSyntax::FindTagName(const WString& str, int& i) const
434
{
435
	String name;
436
	while(i < str.GetCount()) {
437
		if(str[i] == ' ' || str[i] == '>' || str[i] == '/') {
438
			i--;
439
			break;
440
		}
441
		name += str[i];
442
		i++;
443
	}
444
	return name;
445
}
446

  
447
WString TagSyntax::GetCursorLineLeftSide(CodeEditor& editor) const
448
{
449
	int cursor = editor.GetCursor();
450
	int line = editor.GetLinePos(cursor);
451
	WString lineStr = editor.GetWLine(line);
452
	if(cursor < lineStr.GetCount())
453
		lineStr.Trim(cursor);
454
	return lineStr;
455
}
456

  
457
WString TagSyntax::GetCursorLineRightSide(CodeEditor& editor) const
458
{
459
	int cursor = editor.GetCursor();
460
	int line = editor.GetLinePos(cursor);
461
	WString lineStr = editor.GetWLine(line);
462
	if(cursor < lineStr.GetCount())
463
		lineStr.Remove(0, cursor);
464
	else
465
		lineStr = "";
466
	return lineStr;
467
}
468

  
469
bool TagSyntax::IsCursorInsideTag(WString& leftSide, WString& rightSide) const
470
{
471
	for(int i = leftSide.GetCount() - 1; i >= 0; i--) {
472
		wchar c = leftSide[i];
473
		
474
		if(c == '>') {
475
			break;
476
		}
477
		else
478
		if(c == '<') {
479
			return true;
480
		}
481
	}
482
	
483
	return false;
484
}
485

  
294 486
void TagSyntax::Serialize(Stream& s)
295 487
{
296 488
	s % hl_ink
......
302 494
	  % html;
303 495
}
304 496

  
497
void TagSyntax::InitSpecialTags()
498
{
499
	static const char* htmlSpecialTags[] = {
500
		"meta", "link",
501
		"br",
502
		NULL
503
	};
504
	
505
	InitHtmlSpecialTags(htmlSpecialTags);
506
}
507

  
508
void TagSyntax::InitHtmlSpecialTags(const char* specialTags[])
509
{
510
	htmlSpecialTags.Clear();
511
	while(*specialTags)
512
		htmlSpecialTags.Add(*specialTags++);
513
}
514

  
305 515
END_UPP_NAMESPACE
TagSyntax.h (kopia robocza)
1 1
class TagSyntax : public EditorSyntax { // Tag based languages (XML, HTML)
2 2
public:
3
	TagSyntax&  Html(bool b)                                    { html = b; return *this; }
4
	TagSyntax&  Witz(bool b)                                    { witz = b; return *this; }
5
	CSyntax *GetScript()                                        { return status == SCRIPT ? &script : NULL; }
6

  
7
	TagSyntax();
8
	
9
public:
3 10
	virtual void            Clear();
4 11
	virtual void            ScanSyntax(const wchar *ln, const wchar *e, int line, int tab_size);
5 12
	virtual void            Serialize(Stream& s);
......
10 17
	virtual bool            CheckBrackets(CodeEditor& e, int& bpos0, int& bpos);
11 18

  
12 19
private:
13

  
14 20
	enum { TEXT, TAG0, TAG, ENDTAG, ATTR, COMMENT, DECL, PI, SCRIPT };
15 21
	
16 22
	bool    html;
......
22 28

  
23 29
	CSyntax script;     // for <style> or <script>
24 30
	enum { CSS, JS };
25
	int     script_type; 
31
	int     script_type;
26 32

  
27 33
	HighlightOutput *hout;
28 34

  
......
35 41
	void Put(int n = 1)                                         { Put0(hl_ink, n, hl_paper); }
36 42
	void SetPut(int ink, int n = 1, int paper = PAPER_NORMAL)   { Set(ink, paper); Put(n); }
37 43

  
38
public:
39
	TagSyntax&  Html(bool b)                                    { html = b; return *this; }
40
	TagSyntax&  Witz(bool b)                                    { html = b; return *this; }
41
	CSyntax *GetScript()                                        { return status == SCRIPT ? &script : NULL; }
42

  
43
	TagSyntax();
44
private:
45
	bool HasHtmlTags() const;
46
	
47
private:
48
	int  GetIdentationsLevel(CodeEditor& editor) const;
49
	int  GetNewIdnetations(CodeEditor& editor) const;
50
	
51
	Vector< Tuple2<String, int> > SplitTagsByType(const WString& str) const;
52
	String                        FindTagName(const WString& str, int& i) const;
53
	
54
	WString GetCursorLineLeftSide(CodeEditor& editor) const;
55
	WString GetCursorLineRightSide(CodeEditor& editor) const;
56
	
57
	bool IsCursorInsideTag(WString& leftSide, WString& rightSide) const;
58
	
59
private:
60
	void InitSpecialTags();
61
	void InitHtmlSpecialTags(const char* specialTags[]);
62
	
63
private:
64
	Index<String> htmlSpecialTags;
44 65
};