View difference between Paste ID: svCrq6h2 and qGde60U1
SHOW: | | - or go back to the newest paste.
1
# HG changeset patch
2
# User Jérôme LAFORGE <[email protected]>
3-
# Date 1319538202 -7200
3+
# Date 1319607326 -7200
4-
# Node ID dc56e8c124f437c7dd460bbdac413c559cb80f29
4+
# Node ID 230b7804ddb44f11c84229ce1a8a7a6c9605b0a9
5
# Parent  ba1d7ac2e4015d5152859d81b88f145c9681e9be
6
Draft for ChangeLine.
7
8-
diff -r ba1d7ac2e401 -r dc56e8c124f4 include/Scintilla.h
8+
diff -r ba1d7ac2e401 -r 230b7804ddb4 include/Scintilla.h
9
--- a/include/Scintilla.h	mer. oct. 19 14:30:44 2011 +1100
10-
+++ b/include/Scintilla.h	mar. oct. 25 12:23:22 2011 +0200
10+
+++ b/include/Scintilla.h	mer. oct. 26 07:35:26 2011 +0200
11
@@ -831,6 +831,7 @@
12
 #define SC_TECHNOLOGY_DIRECTWRITE 1
13
 #define SCI_SETTECHNOLOGY 2630
14
 #define SCI_GETTECHNOLOGY 2631
15
+#define SCI_CLEARCHANGELINE 2632
16
 #define SCI_STARTRECORD 3001
17
 #define SCI_STOPRECORD 3002
18
 #define SCI_SETLEXER 4001
19-
diff -r ba1d7ac2e401 -r dc56e8c124f4 include/Scintilla.iface
19+
diff -r ba1d7ac2e401 -r 230b7804ddb4 include/Scintilla.iface
20
--- a/include/Scintilla.iface	mer. oct. 19 14:30:44 2011 +1100
21-
+++ b/include/Scintilla.iface	mar. oct. 25 12:23:22 2011 +0200
21+
+++ b/include/Scintilla.iface	mer. oct. 26 07:35:26 2011 +0200
22
@@ -2202,6 +2202,8 @@
23
 # Get the tech.
24
 get int GetTechnology=2631(,)
25
 
26
+fun void ClearChangeLine=2632(,)
27
+
28
 # Start notifying the container of all key presses and commands.
29
 fun void StartRecord=3001(,)
30
 
31-
diff -r ba1d7ac2e401 -r dc56e8c124f4 src/Document.cxx
31+
diff -r ba1d7ac2e401 -r 230b7804ddb4 src/CellBuffer.cxx
32
--- a/src/CellBuffer.cxx	mer. oct. 19 14:30:44 2011 +1100
33-
+++ b/src/Document.cxx	mar. oct. 25 12:23:22 2011 +0200
33+
+++ b/src/CellBuffer.cxx	mer. oct. 26 07:35:26 2011 +0200
34
@@ -9,6 +9,7 @@
35
 #include <string.h>
36
 #include <stdlib.h>
37
 #include <stdarg.h>
38
+#include <deque>
39
 
40
 #include "Platform.h"
41
 
42-
@@ -179,6 +180,7 @@
42+
@@ -74,24 +75,40 @@
43-
 void Document::SetSavePoint() {
43+
 	data = 0;
44-
 	cb.SetSavePoint();
44+
 	lenData = 0;
45-
 	NotifySavePoint(true);
45+
 	mayCoalesce = false;
46-
+	static_cast<LineChange *>(perLineData[ldChange])->PerformSave();
46+
+	lineChangeRemoved = NULL;
47
 }
48
 
49-
 int Document::GetMark(int line) {
49+
 Action::~Action() {
50-
@@ -432,6 +434,26 @@
50+
 	Destroy();
51
 }
52
 
53
-void Action::Create(actionType at_, int position_, char *data_, int lenData_, bool mayCoalesce_) {
54
+void Action::Create(actionType at_, int position_, char *data_, int lenData_, bool mayCoalesce_, std::deque<unsigned char> *lineChangeRemoved_) {
55
 	delete []data;
56
 	position = position_;
57
 	at = at_;
58
 	data = data_;
59
 	lenData = lenData_;
60
 	mayCoalesce = mayCoalesce_;
61
+
62
+	if (lineChangeRemoved_ != NULL) {
63
+		if (lineChangeRemoved == NULL)
64
+			lineChangeRemoved = new std::deque<unsigned char>();
65
+		*lineChangeRemoved = *lineChangeRemoved_;
66
+	} else {
67
+		if (lineChangeRemoved != NULL) {
68
+			delete lineChangeRemoved;
69
+			lineChangeRemoved = NULL;
70
+		}
71
+	}
72
 }
73
 
74
 void Action::Destroy() {
75
 	delete []data;
76
 	data = 0;
77-
@@ -772,6 +794,8 @@
77+
+	if (lineChangeRemoved != NULL) {
78
+		delete lineChangeRemoved;
79
+		lineChangeRemoved = NULL;
80-
 			const char *text = cb.DeleteChars(pos, len, startSequence);
80+
81
 }
82
 
83
 void Action::Grab(Action *source) {
84
@@ -102,6 +119,16 @@
85
 	data = source->data;
86-
@@ -811,6 +835,12 @@
86+
 	lenData = source->lenData;
87
 	mayCoalesce = source->mayCoalesce;
88
+	if (source->lineChangeRemoved != NULL) {
89
+		if (lineChangeRemoved == NULL)
90
+			lineChangeRemoved = new std::deque<unsigned char>();		
91
+		*lineChangeRemoved = *source->lineChangeRemoved;
92
+	} else {
93
+		if (lineChangeRemoved != NULL) {
94
+			delete lineChangeRemoved;
95
+			lineChangeRemoved = NULL;
96
+		}
97
+	}
98
 
99-
@@ -873,6 +903,7 @@
99+
 	// Ownership of source data transferred to this
100
 	source->position = 0;
101
@@ -109,6 +136,10 @@
102
 	source->data = 0;
103-
+					static_cast<LineChange *>(perLineData[ldChange])->PerformUndo(LineFromPosition(action.position));
103+
 	source->lenData = 0;
104
 	source->mayCoalesce = true;
105
+	if (source->lineChangeRemoved != NULL) {
106
+		delete source->lineChangeRemoved;
107-
@@ -896,6 +927,11 @@
107+
+		source->lineChangeRemoved = NULL;
108
+	}
109
 }
110
 
111
 // The undo history stores a sequence of user operations that represent the user's view of the
112
@@ -162,7 +193,7 @@
113
 }
114
 
115
 void UndoHistory::AppendAction(actionType at, int position, char *data, int lengthData,
116
-	bool &startSequence, bool mayCoalesce) {
117
+	bool &startSequence, bool mayCoalesce, std::deque<unsigned char> *lineChangeRemoved) {
118
 	EnsureUndoRoom();
119-
diff -r ba1d7ac2e401 -r dc56e8c124f4 src/Document.h
119+
 	//Platform::DebugPrintf("%% %d action %d %d %d\n", at, position, lengthData, currentAction);
120
 	//Platform::DebugPrintf("^ %d action %d %d\n", actions[currentAction - 1].at,
121-
+++ b/src/Document.h	mar. oct. 25 12:23:22 2011 +0200
121+
@@ -225,7 +256,7 @@
122
 		currentAction++;
123
 	}
124
 	startSequence = oldCurrentAction != currentAction;
125
-	actions[currentAction].Create(at, position, data, lengthData, mayCoalesce);
126
+	actions[currentAction].Create(at, position, data, lengthData, mayCoalesce, lineChangeRemoved);
127
 	currentAction++;
128
 	actions[currentAction].Create(startAction);
129
 	maxAction = currentAction;
130
@@ -422,7 +453,7 @@
131
 }
132
 
133
 // The char* returned is to an allocation owned by the undo history
134
-const char *CellBuffer::DeleteChars(int position, int deleteLength, bool &startSequence) {
135
+const char *CellBuffer::DeleteChars(int position, int deleteLength, bool &startSequence, SplitVector<unsigned char> &lineChange) {
136
 	// InsertString and DeleteChars are the bottleneck though which all changes occur
137
 	PLATFORM_ASSERT(deleteLength > 0);
138
 	char *data = 0;
139
@@ -430,10 +461,43 @@
140
 		if (collectingUndo) {
141
 			// Save into the undo/redo stack, but only the characters - not the formatting
142
 			data = new char[deleteLength];
143
+			int nbLine = 0;
144-
diff -r ba1d7ac2e401 -r dc56e8c124f4 src/Editor.cxx
144+
+			bool ignoreNextCR = false;
145
 			for (int i = 0; i < deleteLength; i++) {
146-
+++ b/src/Editor.cxx	mar. oct. 25 12:23:22 2011 +0200
146+
 				data[i] = substance.ValueAt(position + i);
147-
@@ -1936,8 +1936,30 @@
147+
+				
148
+				switch (data[i]) {
149
+				case '\n':
150
+					nbLine++;
151
+					ignoreNextCR = true;
152
+					break;
153-
+					ViewStyle::LineChange tLineChange;
153+
+				case '\r':
154
+					if (!ignoreNextCR)
155-
+						if (pdoc->IsChangeLineModified(lineDoc)) {
155+
+						nbLine++;
156-
+							tLineChange = ViewStyle::lineChangeModified;
156+
+					ignoreNextCR = false;
157
+					break;
158-
+							if (pdoc->HasChangeLineBeenSaved(lineDoc))
158+
+				default:
159-
+								tLineChange = ViewStyle::lineChangeSaved;
159+
+					ignoreNextCR = false;
160-
+							else
160+
+					break;
161-
+								tLineChange = ViewStyle::lineChangeUnmodified;
161+
+				}
162
 			}
163
-			uh.AppendAction(removeAction, position, data, deleteLength, startSequence);
164
+			
165
+			std::deque<unsigned char> *plineChangeRemoved = NULL;
166
+			std::deque<unsigned char> lineChangeRemoved;
167
+			if (nbLine > 0) {
168
+				plineChangeRemoved = &lineChangeRemoved;
169
+				nbLine += 1; // Get last line too.
170
+				int line = LineFromPosition(position);
171-
+								sprintf(number, "%d", lineDoc + 1);
171+
+				unsigned char curLineChangeRemoved;
172
+				for (; nbLine > 0; nbLine--, line++) {
173
+					if (line < lineChange.Length())
174
+						curLineChangeRemoved = lineChange[line];
175
+					else
176
+						curLineChangeRemoved = 0;
177
+					lineChangeRemoved.push_back(curLineChangeRemoved);
178
+				}
179
+			}
180-
@@ -1952,9 +1974,22 @@
180+
+			uh.AppendAction(removeAction, position, data, deleteLength, startSequence, true, plineChangeRemoved);
181
 		}
182
 
183
 		BasicDeleteChars(position, deleteLength);
184
diff -r ba1d7ac2e401 -r 230b7804ddb4 src/CellBuffer.h
185
--- a/src/CellBuffer.h	mer. oct. 19 14:30:44 2011 +1100
186
+++ b/src/CellBuffer.h	mer. oct. 26 07:35:26 2011 +0200
187
@@ -12,6 +12,10 @@
188
 namespace Scintilla {
189
 #endif
190
 
191
+#include <deque>
192
+
193
+#include "SplitVector.h"
194
+
195
 // Interface to per-line data that wants to see each line insertion and deletion
196
 class PerLine {
197
 public:
198
@@ -77,10 +81,11 @@
199
 	char *data;
200
 	int lenData;
201
 	bool mayCoalesce;
202
+	std::deque<unsigned char> *lineChangeRemoved;
203
 
204-
@@ -4031,6 +4066,8 @@
204+
 	Action();
205
 	~Action();
206
-	void Create(actionType at_, int position_=0, char *data_=0, int lenData_=0, bool mayCoalesce_=true);
207
+	void Create(actionType at_, int position_=0, char *data_=0, int lenData_=0, bool mayCoalesce_=true, std::deque<unsigned char> *lineChangeRemoved_=NULL);
208
 	void Destroy();
209
 	void Grab(Action *source);
210
 };
211
@@ -102,7 +107,7 @@
212
 	UndoHistory();
213-
@@ -4280,6 +4317,8 @@
213+
 	~UndoHistory();
214
 
215
-	void AppendAction(actionType at, int position, char *data, int length, bool &startSequence, bool mayCoalesce=true);
216
+	void AppendAction(actionType at, int position, char *data, int length, bool &startSequence, bool mayCoalesce=true, std::deque<unsigned char> *lineChangeRemoved=NULL);
217
 
218
 	void BeginUndoAction();
219
 	void EndUndoAction();
220
@@ -173,7 +178,7 @@
221
 	bool SetStyleAt(int position, char styleValue, char mask='\377');
222-
@@ -4289,6 +4328,8 @@
222+
 	bool SetStyleFor(int position, int length, char styleValue, char mask);
223
 
224
-	const char *DeleteChars(int position, int deleteLength, bool &startSequence);
225
+	const char *DeleteChars(int position, int deleteLength, bool &startSequence, SplitVector<unsigned char> &changeLine);
226
 
227
 	bool IsReadOnly() const;
228
 	void SetReadOnly(bool set);
229
diff -r ba1d7ac2e401 -r 230b7804ddb4 src/Document.cxx
230
--- a/src/Document.cxx	mer. oct. 19 14:30:44 2011 +1100
231-
@@ -4343,6 +4384,8 @@
231+
+++ b/src/Document.cxx	mer. oct. 26 07:35:26 2011 +0200
232
@@ -118,6 +118,7 @@
233
 	perLineData[ldState] = new LineState();
234
 	perLineData[ldMargin] = new LineAnnotation();
235
 	perLineData[ldAnnotation] = new LineAnnotation();
236
+	perLineData[ldChange] = new LineChange();
237
 
238
 	cb.SetPerLine(this);
239
 
240-
@@ -7609,6 +7652,7 @@
240+
@@ -432,6 +433,26 @@
241
 	highlightDelimiter.firstChangeableLineAfter = firstChangeableLineAfter;
242
 }
243
 
244
+void Document::ClearChangeLine() {
245
+	static_cast<LineChange *>(perLineData[ldChange])->ClearAll();
246
+}
247
+
248-
@@ -9247,6 +9291,10 @@
248+
249
+	return static_cast<LineChange *>(perLineData[ldChange])->GetLineChange(line);
250
+}
251
+
252
+bool Document::HasChangeLineBeenSaved(int line) {
253
+	return static_cast<LineChange *>(perLineData[ldChange])->HasBeenSaved(line);
254
+}
255
+
256
+bool Document::IsChangeLineModified(int line) {
257
+	return static_cast<LineChange *>(perLineData[ldChange])->IsModified(line);
258
+}
259-
diff -r ba1d7ac2e401 -r dc56e8c124f4 src/PerLine.cxx
259+
260
+bool Document::HasChangeLineOccured() {
261-
+++ b/src/PerLine.cxx	mar. oct. 25 12:23:22 2011 +0200
261+
262-
@@ -500,3 +500,78 @@
262+
263
+
264
 int Document::ClampPositionIntoDocument(int pos) {
265
 	return Platform::Clamp(pos, 0, Length());
266
 }
267
@@ -771,7 +792,9 @@
268
 			int prevLinesTotal = LinesTotal();
269
 			bool startSavePoint = cb.IsSavePoint();
270
 			bool startSequence = false;
271
-			const char *text = cb.DeleteChars(pos, len, startSequence);
272
+			const char *text = cb.DeleteChars(pos, len, startSequence, static_cast<LineChange *>(perLineData[ldChange])->lineChange);
273
+			if (startSequence)
274
+				static_cast<LineChange *>(perLineData[ldChange])->ModifyLines(LineFromPosition(pos));
275
 			if (startSavePoint && cb.IsCollectingUndo())
276
 				NotifySavePoint(!startSavePoint);
277
 			if ((pos < Length()) || (pos == 0))
278
@@ -811,6 +834,12 @@
279
 			bool startSavePoint = cb.IsSavePoint();
280
 			bool startSequence = false;
281
 			const char *text = cb.InsertString(position, s, insertLength, startSequence);
282
+			int line = LineFromPosition(position);
283
+			bool isEmptyLine = text && *text && (*text == '\n' || *text == '\r') && LineStart(line) == position;
284
+			if (startSequence &&
285
+			        // If empty line is inserted, then the next line is shift by one line (no modification).
286
+			        !isEmptyLine)
287
+				static_cast<LineChange *>(perLineData[ldChange])->ModifyLines(line);
288
 			if (startSavePoint && cb.IsCollectingUndo())
289-
+	if ((lineChange[line] & maskNumber) < maskNumber) {
289+
290
 			ModifiedAt(position);
291-
+		hasChangeOccured = true;
291+
@@ -850,6 +879,15 @@
292
 									SC_MOD_BEFOREDELETE | SC_PERFORMED_UNDO, action));
293
 				}
294
 				cb.PerformUndoStep();
295
+
296
+				if (action.lineChangeRemoved != NULL) {
297
+					std::deque<unsigned char>::iterator it = action.lineChangeRemoved->begin();
298-
+	if ((lineChange[line] & maskNumber) > 1) {// 0 is equivalent at noChange.
298+
+					int line = LineFromPosition(action.position);
299
+					for (; it != action.lineChangeRemoved->end(); it++, line++) {
300-
+		hasChangeOccured = true;
300+
+						static_cast<LineChange *>(perLineData[ldChange])->SetChangeLine(line, *it);
301
+					}
302
+				}
303
+
304
 				int cellPosition = action.position;
305-
+	ModifyLines(line);
305+
 				if (action.at != containerAction) {
306
 					ModifiedAt(cellPosition);
307
@@ -873,6 +911,8 @@
308
 					modFlags |= SC_LASTSTEPINUNDOREDO;
309
 					if (multiLine)
310
 						modFlags |= SC_MULTILINEUNDOREDO;
311
+					if (action.at != removeAction || !multiLine)
312
+						static_cast<LineChange *>(perLineData[ldChange])->PerformUndo(LineFromPosition(action.position));
313
 				}
314
 				NotifyModified(DocModification(modFlags, cellPosition, action.lenData,
315-
+void LineChange::PerformSave() {
315+
316
@@ -896,6 +936,11 @@
317-
+		if (lineChange[i])
317+
318
 			bool multiLine = false;
319
 			int steps = cb.StartRedo();
320
+			int line = LineFromPosition(cb.GetRedoStep().position);
321
+			const char *data = cb.GetRedoStep().data;
322
+			bool isEmptyLine = data && *data && (*data == '\n' || *data == '\r') && LineStart(line) == cb.GetRedoStep().position;
323-
+	lineChange.DeleteAll();
323+
324
+				static_cast<LineChange *>(perLineData[ldChange])->PerformRedo(LineFromPosition(cb.GetRedoStep().position));
325
 			for (int step = 0; step < steps; step++) {
326
 				const int prevLinesTotal = LinesTotal();
327
 				const Action &action = cb.GetRedoStep();
328
@@ -1834,6 +1879,9 @@
329
 	for (int i = 0; i < lenWatchers; i++) {
330
 		watchers[i].watcher->NotifySavePoint(this, watchers[i].userData, atSavePoint);
331
 	}
332
+	if (atSavePoint)
333
+		// Here, we are sure that document is clean. So we force to clean all lines that stay dirty.
334
+		static_cast<LineChange *>(perLineData[ldChange])->ReachSavePoint();
335
 }
336
 
337
 void Document::NotifyModified(DocModification mh) {
338
diff -r ba1d7ac2e401 -r 230b7804ddb4 src/Document.h
339
--- a/src/Document.h	mer. oct. 19 14:30:44 2011 +1100
340
+++ b/src/Document.h	mer. oct. 26 07:35:26 2011 +0200
341-
diff -r ba1d7ac2e401 -r dc56e8c124f4 src/PerLine.h
341+
342
 	int lenWatchers;
343-
+++ b/src/PerLine.h	mar. oct. 25 12:23:22 2011 +0200
343+
344-
@@ -114,6 +114,36 @@
344+
345
-	enum lineData { ldMarkers, ldLevels, ldState, ldMargin, ldAnnotation, ldSize };
346
+	enum lineData { ldMarkers, ldLevels, ldState, ldMargin, ldAnnotation, ldChange, ldSize };
347
 	PerLine *perLineData[ldSize];
348
 
349
 	bool matchesValid;
350
@@ -342,6 +342,12 @@
351
 	int GetLastChild(int lineParent, int level=-1, int lastLine=-1);
352
 	int GetFoldParent(int line);
353-
+		noChange = 0x40
353+
354
+	
355
+	void ClearChangeLine();
356
+	unsigned char GetChangeLine(int line);
357
+	bool HasChangeLineBeenSaved(int line);
358
+	bool IsChangeLineModified(int line);
359
+	bool HasChangeLineOccured();
360
 
361
 	void Indent(bool forwards);
362
 	int ExtendWordSelect(int pos, int delta, bool onlyWordCharacters=false);
363
diff -r ba1d7ac2e401 -r 230b7804ddb4 src/Editor.cxx
364
--- a/src/Editor.cxx	mer. oct. 19 14:30:44 2011 +1100
365
+++ b/src/Editor.cxx	mer. oct. 26 07:35:26 2011 +0200
366
@@ -1825,6 +1825,7 @@
367
 			int folderEnd = SubstituteMarkerIfEmpty(SC_MARKNUM_FOLDEREND,
368
 			        SC_MARKNUM_FOLDER);
369-
+	void PerformSave();
369+
370
+			ViewStyle::LineChange tLineChange;
371
 			while ((visibleLine < cs.LinesDisplayed()) && yposScreen < rcMargin.bottom) {
372
 
373
 				PLATFORM_ASSERT(visibleLine < cs.LinesDisplayed());
374
@@ -1839,6 +1840,15 @@
375
 
376
 				bool headWithTail = false;
377
 
378
+				if (pdoc->IsChangeLineModified(lineDoc)) {
379
+					tLineChange = ViewStyle::lineChangeModified;
380
+				} else {
381-
diff -r ba1d7ac2e401 -r dc56e8c124f4 src/ViewStyle.h
381+
+					if (pdoc->HasChangeLineBeenSaved(lineDoc))
382
+						tLineChange = ViewStyle::lineChangeSaved;
383-
+++ b/src/ViewStyle.h	mar. oct. 25 12:23:22 2011 +0200
383+
+					else
384
+						tLineChange = ViewStyle::lineChangeUnmodified;
385
+				}
386
+
387
 				if (vs.ms[margin].mask & SC_MASK_FOLDERS) {
388
 					// Decide which fold indicator should be displayed
389
 					int level = pdoc->GetLevel(lineDoc);
390
@@ -1936,8 +1946,24 @@
391
 				if (vs.ms[margin].style == SC_MARGIN_NUMBER) {
392
 					char number[100];
393
 					number[0] = '\0';
394
-					if (firstSubLine)
395
-						sprintf(number, "%d", lineDoc + 1);
396
+					if (firstSubLine) {
397
+						if (false) { // for testing and helping during the developpment process. Have to be removed after.
398
+							unsigned char lineChange = pdoc->GetChangeLine(lineDoc);
399
+							if (pdoc->IsChangeLineModified(lineDoc)) {
400
+								if (pdoc->HasChangeLineBeenSaved(lineDoc))
401
+									sprintf(number, "%2X#%d", lineChange, lineDoc + 1);
402
+								else
403
+									sprintf(number, "%2X*%d", lineChange, lineDoc + 1);
404
+							} else {
405
+								if (pdoc->HasChangeLineBeenSaved(lineDoc))
406
+									sprintf(number, "%2X#%d", lineChange, lineDoc + 1);
407
+								else
408
+									sprintf(number, "%2X-%d", lineChange, lineDoc + 1);
409
+							}
410
+						} else {
411
+							sprintf(number, "%d", lineDoc + 1);
412
+						}
413
+					}
414
 					if (foldFlags & SC_FOLDFLAG_LEVELNUMBERS) {
415
 						int lev = pdoc->GetLevel(lineDoc);
416
 						sprintf(number, "%c%c %03X %03X",
417
@@ -1952,9 +1978,22 @@
418
 					int width = surface->WidthText(vs.styles[STYLE_LINENUMBER].font, number, istrlen(number));
419
 					int xpos = rcNumber.right - width - 3;
420
 					rcNumber.left = xpos;
421
+					ColourDesired fore = vs.styles[STYLE_LINENUMBER].fore;
422
+					switch (tLineChange) {
423
+					case ViewStyle::lineChangeSaved:
424
+						fore = ColourDesired(0, 255, 0);
425
+						break;
426
+					case ViewStyle::lineChangeModified:
427
+						fore = ColourDesired(255, 0, 0);
428
+						break;
429
+					case ViewStyle::lineChangeUnmodified:
430
+						//do nothing
431
+						break;
432
+					}
433
 					surface->DrawTextNoClip(rcNumber, vs.styles[STYLE_LINENUMBER].font,
434
 					        rcNumber.top + vs.maxAscent, number, istrlen(number),
435
-					        vs.styles[STYLE_LINENUMBER].fore,
436
+					        fore,
437
+					        //vs.styles[STYLE_LINENUMBER].fore,
438
 					        vs.styles[STYLE_LINENUMBER].back);
439
 				} else if (vs.ms[margin].style == SC_MARGIN_TEXT || vs.ms[margin].style == SC_MARGIN_RTEXT) {
440
 					if (firstSubLine) {
441
@@ -4031,6 +4070,8 @@
442
 						}
443
 					}
444
 				}
445
+				if (pdoc->HasChangeLineOccured())
446
+					RedrawSelMargin();
447
 			}
448
 		}
449
 	}
450
@@ -4280,6 +4321,8 @@
451
 		if (newPos >= 0)
452
 			SetEmptySelection(newPos);
453
 		EnsureCaretVisible();
454
+		if (pdoc->HasChangeLineOccured())
455
+			RedrawSelMargin();
456
 	}
457
 }
458
 
459
@@ -4289,6 +4332,8 @@
460
 		if (newPos >= 0)
461
 			SetEmptySelection(newPos);
462
 		EnsureCaretVisible();
463
+		if (pdoc->HasChangeLineOccured())
464
+			RedrawSelMargin();
465
 	}
466
 }
467
 
468
@@ -4343,6 +4388,8 @@
469
 	sel.RemoveDuplicates();
470
 	// Avoid blinking during rapid typing:
471
 	ShowCaretAtCurrentPosition();
472
+	if (pdoc->HasChangeLineOccured())
473
+		RedrawSelMargin();
474
 }
475
 
476
 void Editor::NotifyFocus(bool) {}
477
@@ -7609,6 +7656,8 @@
478
 
479
 	case SCI_SETSAVEPOINT:
480
 		pdoc->SetSavePoint();
481
+		if (pdoc->HasChangeLineOccured())
482
+			RedrawSelMargin();
483
 		break;
484
 
485
 	case SCI_GETSTYLEDTEXT: {
486
@@ -9247,6 +9296,12 @@
487
 	
488
 	case SCI_GETTECHNOLOGY:
489
 		return technology;
490
+	
491
+	case SCI_CLEARCHANGELINE:
492
+		pdoc->ClearChangeLine();
493
+		if (pdoc->HasChangeLineOccured())
494
+			RedrawSelMargin();
495
+		break;
496
 
497
 	default:
498
 		return DefWndProc(iMessage, wParam, lParam);
499
diff -r ba1d7ac2e401 -r 230b7804ddb4 src/PerLine.cxx
500
--- a/src/PerLine.cxx	mer. oct. 19 14:30:44 2011 +1100
501
+++ b/src/PerLine.cxx	mer. oct. 26 07:35:26 2011 +0200
502
@@ -500,3 +500,104 @@
503
 	else
504
 		return 0;
505
 }
506
+
507
+LineChange::~LineChange(){
508
+}
509
+
510
+void LineChange::Init(){
511
+}
512
+
513
+void LineChange::InsertLine(int line){
514
+	if (lineChange.Length() < line)
515
+		lineChange.EnsureLength(line);
516
+	lineChange.Insert(line, noChange + 1);
517
+}
518
+
519
+void LineChange::RemoveLine(int line){
520
+	if (lineChange.Length() && (line < lineChange.Length()))
521
+		lineChange.Delete(line);
522
+}
523
+
524
+void LineChange::ModifyLines(int line) {
525
+	if (lineChange.Length() <= line)
526
+		lineChange.EnsureLength(line + 1);
527
+	if (lineChange[line] == 0)
528
+		lineChange[line] = noChange;
529
+	if ((lineChange[line] & maskNumber) < noChange){
530
+		lineChange[line] = maskSticky; // Impossible to come back to no change, so we stick the status at maskSticky.
531
+		//hasChangeOccured = true;
532
+	} else if (lineChange[line] != maskSticky && (lineChange[line] & maskNumber) < maskNumber) {
533
+		lineChange[line] += 1;
534
+		hasChangeOccured = lineChange[line] == noChange || lineChange[line] == noChange + 1; // perform redraw only if needed.
535
+		//hasChangeOccured = true;
536
+	}
537
+}
538
+
539
+void LineChange::PerformUndo(int line) {
540
+	if (lineChange.Length() <= line)
541
+		lineChange.EnsureLength(line + 1);
542
+	if (lineChange[line] != maskSticky && (lineChange[line] & maskNumber) > 1) {
543
+		lineChange[line] -= 1;
544
+		hasChangeOccured = lineChange[line] == noChange || lineChange[line] == noChange - 1; // perform redraw only if needed.
545
+		//hasChangeOccured = true;
546
+	}
547
+}
548
+
549
+void LineChange::PerformRedo(int line) {
550
+	if (lineChange.Length() <= line)
551
+		lineChange.EnsureLength(line + 1);
552
+	if (lineChange[line] == 0)
553
+		lineChange[line] = noChange;
554
+	if (lineChange[line] != maskSticky && (lineChange[line] & maskNumber) < maskNumber) {
555
+		lineChange[line] += 1;
556
+		hasChangeOccured = lineChange[line] == noChange || lineChange[line] == noChange + 1; // perform redraw only if needed.
557
+		//hasChangeOccured = true;
558
+	}
559
+}
560
+
561
+unsigned char LineChange::GetLineChange(int line) {
562
+	if (lineChange.Length() &&  (line >= 0) && (line < lineChange.Length()))
563
+		return lineChange[line];
564
+	else
565
+		return noChange;
566
+}
567
+
568
+void LineChange::ReachSavePoint() {
569
+	for (int i = 0; i < lineChange.Length(); i++) {
570
+		if ((lineChange[i] & maskNumber) != noChange) {
571
+			lineChange[i] = maskHasBeenSaved | noChange;
572
+			hasChangeOccured = true;
573
+		}
574
+	}
575
+}
576
+
577
+void LineChange::SetChangeLine(int line, unsigned char status) {
578
+	if (lineChange.Length() <= line)
579
+		lineChange.EnsureLength(line + 1);
580
+	lineChange[line] = status;
581
+}
582
+
583
+void LineChange::ClearAll() {
584
+	for (int i = 0; i < lineChange.Length(); i++) {
585
+		if (lineChange[i] != noChange) {
586
+			lineChange[i] = noChange;
587
+			hasChangeOccured = true;
588
+		}
589
+	}
590
+}
591
+
592
+bool LineChange::HasBeenSaved(int line) {
593
+	unsigned char status = GetLineChange(line);
594
+	return (status & maskHasBeenSaved) != 0;
595
+}
596
+
597
+bool LineChange::IsModified(int line) {
598
+	unsigned char status = GetLineChange(line);
599
+	return (status & maskNumber) != noChange && (status & maskNumber) != 0;
600
+}
601
+
602
+bool LineChange::HasChangeOccuredAndClear() {
603
+	bool b = hasChangeOccured;
604
+	hasChangeOccured = false;
605
+	return b;
606
+}
607
diff -r ba1d7ac2e401 -r 230b7804ddb4 src/PerLine.h
608
--- a/src/PerLine.h	mer. oct. 19 14:30:44 2011 +1100
609
+++ b/src/PerLine.h	mer. oct. 26 07:35:26 2011 +0200
610
@@ -114,6 +114,38 @@
611
 	int Lines(int line) const;
612
 };
613
 
614
+class LineChange : public PerLine {
615
+private:
616
+	bool hasChangeOccured;
617
+public:
618
+	enum {
619
+		maskHasBeenSaved = 0x80,
620
+		maskNumber = 0x7F,
621
+		noChange = 0x40,
622
+		maskSticky = 0xFF 
623
+	};
624
+	SplitVector<unsigned char> lineChange;
625
+	LineChange() {
626
+		hasChangeOccured = false;
627
+	}
628
+	virtual ~LineChange();
629
+	virtual void Init();
630
+	virtual void InsertLine(int line);
631
+	virtual void RemoveLine(int line);
632
+
633
+	void ModifyLines(int line);
634
+	void PerformUndo(int line);
635
+	void PerformRedo(int line);
636
+	void ReachSavePoint();
637
+	void SetChangeLine(int line, unsigned char status);
638
+	void ClearAll();
639
+	
640
+	unsigned char GetLineChange (int line);
641
+	bool HasBeenSaved(int line);
642
+	bool IsModified(int line);
643
+	bool HasChangeOccuredAndClear();
644
+};
645
+
646
 #ifdef SCI_NAMESPACE
647
 }
648
 #endif
649
diff -r ba1d7ac2e401 -r 230b7804ddb4 src/ViewStyle.h
650
--- a/src/ViewStyle.h	mer. oct. 19 14:30:44 2011 +1100
651
+++ b/src/ViewStyle.h	mer. oct. 26 07:35:26 2011 +0200
652
@@ -61,6 +61,7 @@
653
  */
654
 class ViewStyle {
655
 public:
656
+	enum LineChange {lineChangeUnmodified, lineChangeModified, lineChangeSaved};
657
 	FontNames fontNames;
658
 	FontRealised *frFirst;
659
 	size_t stylesSize;
660
661