aboutsummaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/CellBuffer.cxx316
-rw-r--r--src/CellBuffer.h49
-rw-r--r--src/Document.cxx48
-rw-r--r--src/Document.h5
-rw-r--r--src/Editor.cxx98
-rw-r--r--src/Editor.h2
-rw-r--r--src/KeyMap.cxx45
-rw-r--r--src/KeyMap.h1
-rw-r--r--src/LexCPP.cxx23
9 files changed, 420 insertions, 167 deletions
diff --git a/src/CellBuffer.cxx b/src/CellBuffer.cxx
index 777688511..4d667dcf4 100644
--- a/src/CellBuffer.cxx
+++ b/src/CellBuffer.cxx
@@ -344,31 +344,199 @@ void Action::Grab(Action *source) {
source->lenData = 0;
}
-CellBuffer::CellBuffer(int initialLength) {
- body = new char[initialLength];
- size = initialLength;
- length = 0;
- part1len = 0;
- gaplen = initialLength;
- part2body = body + gaplen;
- readOnly = false;
+// The undo history stores a sequence of user operations that represent the user's view of the
+// commands executed on the text.
+// Each user operation contains a sequence of text insertion and text deletion actions.
+// All the user operations are stored in a list of individual actions with 'start' actions used
+// as delimiters between user operations.
+// Initially there is one start action in the history.
+// As each action is performed, it is recorded in the history. The action may either become
+// part of the current user operation or may start a new user operation. If it is to be part of the
+// current operation, then it overwrites the current last action. If it is to be part of a new
+// operation, it is appended after the current last action.
+// After writing the new action, a new start action is appended at the end of the history.
+// The decision of whether to start a new user operation is based upon two factors. If a
+// compound operation has been explicitly started by calling BeginUndoAction and no matching
+// EndUndoAction (these calls nest) has been called, then the action is coalesced into the current
+// operation. If there is no outstanding BeginUndoAction call then a new operation is started
+// unless it looks as if the new action is caused by the user typing or deleting a stream of text.
+// Sequences that look like typing or deletion are coalesced into a single user operation.
+
+UndoHistory::UndoHistory() {
lenActions = 100;
actions = new Action[lenActions];
maxAction = 0;
currentAction = 0;
- collectingUndo = undoCollectAutoStart;
undoSequenceDepth = 0;
savePoint = 0;
actions[currentAction].Create(startAction);
}
+UndoHistory::~UndoHistory() {
+ delete []actions;
+ actions = 0;
+}
+
+void UndoHistory::EnsureUndoRoom() {
+ //Platform::DebugPrintf("%% %d action %d %d %d\n", at, position, length, currentAction);
+ if (currentAction >= 2) {
+ // Have to test that there is room for 2 more actions in the array
+ // as two actions may be created by this function
+ if (currentAction >= (lenActions - 2)) {
+ // Run out of undo nodes so extend the array
+ int lenActionsNew = lenActions * 2;
+ Action *actionsNew = new Action[lenActionsNew];
+ if (!actionsNew)
+ return;
+ for (int act = 0; act <= currentAction; act++)
+ actionsNew[act].Grab(&actions[act]);
+ delete []actions;
+ lenActions = lenActionsNew;
+ actions = actionsNew;
+ }
+ }
+}
+
+void UndoHistory::AppendAction(actionType at, int position, char *data, int lengthData) {
+ EnsureUndoRoom();
+ Platform::DebugPrintf("%% %d action %d %d %d\n", at, position, lengthData, currentAction);
+ Platform::DebugPrintf("^ %d action %d %d\n", actions[currentAction - 1].at,
+ actions[currentAction - 1].position, actions[currentAction - 1].lenData);
+ if (0 == undoSequenceDepth) {
+ // Top level actions may not always be coalesced
+ if (currentAction >= 2) {
+ Action &actPrevious = actions[currentAction - 1];
+ // See if current action can be coalesced into previous action
+ // Will work if both are inserts or deletes and position is same
+ if (at != actPrevious.at) {
+ currentAction++;
+ } else if (currentAction == savePoint) {
+ currentAction++;
+ } else if ((at == removeAction) &&
+ ((position + lengthData * 2) != actPrevious.position)) {
+ // Removals must be at same position to coalesce
+ currentAction++;
+ } else if ((at == insertAction) &&
+ (position != (actPrevious.position + actPrevious.lenData*2))) {
+ // Insertions must be immediately after to coalesce
+ currentAction++;
+ } else {
+ Platform::DebugPrintf("action coalesced\n");
+ }
+ } else {
+ currentAction++;
+ }
+ }
+ actions[currentAction].Create(at, position, data, lengthData);
+ //if ((collectingUndo == undoCollectAutoStart) && (0 == undoSequenceDepth)) {
+ currentAction++;
+ actions[currentAction].Create(startAction);
+ //}
+ maxAction = currentAction;
+}
+
+void UndoHistory::BeginUndoAction() {
+ EnsureUndoRoom();
+ if (undoSequenceDepth == 0) {
+ if (actions[currentAction].at != startAction) {
+ currentAction++;
+ actions[currentAction].Create(startAction);
+ maxAction = currentAction;
+ }
+ }
+ undoSequenceDepth++;
+}
+
+void UndoHistory::EndUndoAction() {
+ EnsureUndoRoom();
+ undoSequenceDepth--;
+ if (0 == undoSequenceDepth) {
+ if (actions[currentAction].at != startAction) {
+ currentAction++;
+ actions[currentAction].Create(startAction);
+ maxAction = currentAction;
+ }
+ }
+}
+
+void UndoHistory::DropUndoSequence() {
+ undoSequenceDepth = 0;
+}
+
+void UndoHistory::DeleteUndoHistory() {
+ for (int i = 1; i < maxAction; i++)
+ actions[i].Destroy();
+ maxAction = 0;
+ currentAction = 0;
+ savePoint = 0;
+}
+
+void UndoHistory::SetSavePoint() {
+ savePoint = currentAction;
+}
+
+bool UndoHistory::IsSavePoint() const {
+ return savePoint == currentAction;
+}
+
+bool UndoHistory::CanUndo() const {
+ return (currentAction > 0) && (maxAction > 0);
+}
+
+int UndoHistory::StartUndo() {
+ // Drop any trailing startAction
+ if (actions[currentAction].at == startAction && currentAction > 0)
+ currentAction--;
+
+ // Count the steps in this action
+ int act = currentAction;
+ while (actions[act].at != startAction && act > 0) {
+ act--;
+ }
+ return currentAction - act;
+}
+
+const Action &UndoHistory::UndoStep() {
+ return actions[currentAction--];
+}
+
+bool UndoHistory::CanRedo() const {
+ return maxAction > currentAction;
+}
+
+int UndoHistory::StartRedo() {
+ // Drop any leading startAction
+ if (actions[currentAction].at == startAction && currentAction < maxAction)
+ currentAction++;
+
+ // Count the steps in this action
+ int act = currentAction;
+ while (actions[act].at != startAction && act < maxAction) {
+ act++;
+ }
+ return act - currentAction;
+}
+
+const Action &UndoHistory::RedoStep() {
+ return actions[currentAction++];
+}
+
+CellBuffer::CellBuffer(int initialLength) {
+ body = new char[initialLength];
+ size = initialLength;
+ length = 0;
+ part1len = 0;
+ gaplen = initialLength;
+ part2body = body + gaplen;
+ readOnly = false;
+ collectingUndo = undoCollectAutoStart;
+}
+
CellBuffer::~CellBuffer() {
delete []body;
body = 0;
- delete []actions;
- actions = 0;
}
void CellBuffer::GapTo(int position) {
@@ -486,7 +654,7 @@ const char *CellBuffer::InsertString(int position, char *s, int insertLength) {
for (int i = 0; i < insertLength / 2; i++) {
data[i] = s[i * 2];
}
- AppendAction(insertAction, position, data, insertLength / 2);
+ uh.AppendAction(insertAction, position, data, insertLength / 2);
}
BasicInsertString(position, s, insertLength);
@@ -525,48 +693,6 @@ bool CellBuffer::SetStyleFor(int position, int lengthStyle, char style, char mas
return changed;
}
-void CellBuffer::EnsureUndoRoom() {
- //Platform::DebugPrintf("%% %d action %d %d %d\n", at, position, length, currentAction);
- if (currentAction >= 2) {
- // Have to test that there is room for 2 more actions in the array
- // as two actions may be created by this function
- if (currentAction >= (lenActions - 2)) {
- // Run out of undo nodes so extend the array
- int lenActionsNew = lenActions * 2;
- Action *actionsNew = new Action[lenActionsNew];
- if (!actionsNew)
- return;
- for (int act = 0; act <= currentAction; act++)
- actionsNew[act].Grab(&actions[act]);
- delete []actions;
- lenActions = lenActionsNew;
- actions = actionsNew;
- }
- }
-}
-
-void CellBuffer::AppendAction(actionType at, int position, char *data, int lengthData) {
- EnsureUndoRoom();
- //Platform::DebugPrintf("%% %d action %d %d %d\n", at, position, lengthData, currentAction);
- if (currentAction >= 2) {
- // See if current action can be coalesced into previous action
- // Will work if both are inserts or deletes and position is same or two different
- if ((at != actions[currentAction - 1].at) || (abs(position - actions[currentAction - 1].position) > 2)) {
- currentAction++;
- } else if (currentAction == savePoint) {
- currentAction++;
- }
- } else {
- currentAction++;
- }
- actions[currentAction].Create(at, position, data, lengthData);
- if ((collectingUndo == undoCollectAutoStart) && (0 == undoSequenceDepth)) {
- currentAction++;
- actions[currentAction].Create(startAction);
- }
- maxAction = currentAction;
-}
-
const char *CellBuffer::DeleteChars(int position, int deleteLength) {
// InsertString and DeleteChars are the bottleneck though which all changes occur
char *data = 0;
@@ -577,7 +703,7 @@ const char *CellBuffer::DeleteChars(int position, int deleteLength) {
for (int i = 0; i < deleteLength / 2; i++) {
data[i] = ByteAt(position + i * 2);
}
- AppendAction(removeAction, position, data, deleteLength / 2);
+ uh.AppendAction(removeAction, position, data, deleteLength / 2);
}
BasicDeleteChars(position, deleteLength);
@@ -616,11 +742,11 @@ void CellBuffer::SetReadOnly(bool set) {
}
void CellBuffer::SetSavePoint() {
- savePoint = currentAction;
+ uh.SetSavePoint();
}
bool CellBuffer::IsSavePoint() {
- return savePoint == currentAction;
+ return uh.IsSavePoint();
}
int CellBuffer::AddMark(int line, int markerNum) {
@@ -659,7 +785,7 @@ int CellBuffer::LineFromHandle(int markerHandle) {
// Without undo
void CellBuffer::BasicInsertString(int position, char *s, int insertLength) {
- //Platform::DebugPrintf("Inserting at %d for %d\n", position, insertLength);
+ Platform::DebugPrintf("Inserting at %d for %d\n", position, insertLength);
if (insertLength == 0)
return;
RoomFor(insertLength);
@@ -719,7 +845,7 @@ void CellBuffer::BasicInsertString(int position, char *s, int insertLength) {
}
void CellBuffer::BasicDeleteChars(int position, int deleteLength) {
- //Platform::DebugPrintf("Deleting at %d for %d\n", position, deleteLength);
+ Platform::DebugPrintf("Deleting at %d for %d\n", position, deleteLength);
if (deleteLength == 0)
return;
@@ -792,7 +918,7 @@ void CellBuffer::BasicDeleteChars(int position, int deleteLength) {
undoCollectionType CellBuffer::SetUndoCollection(undoCollectionType collectUndo) {
collectingUndo = collectUndo;
- undoSequenceDepth = 0;
+ uh.DropUndoSequence();
return collectingUndo;
}
@@ -800,69 +926,28 @@ bool CellBuffer::IsCollectingUndo() {
return collectingUndo;
}
-void CellBuffer::AppendUndoStartAction() {
- EnsureUndoRoom();
- // Finish any currently active undo sequence
- undoSequenceDepth = 0;
- if (actions[currentAction].at != startAction) {
- undoSequenceDepth++;
- currentAction++;
- actions[currentAction].Create(startAction);
- maxAction = currentAction;
- }
-}
-
void CellBuffer::BeginUndoAction() {
- EnsureUndoRoom();
- if (undoSequenceDepth == 0) {
- if (actions[currentAction].at != startAction) {
- currentAction++;
- actions[currentAction].Create(startAction);
- maxAction = currentAction;
- }
- }
- undoSequenceDepth++;
+ uh.BeginUndoAction();
}
void CellBuffer::EndUndoAction() {
- EnsureUndoRoom();
- undoSequenceDepth--;
- if (0 == undoSequenceDepth) {
- if (actions[currentAction].at != startAction) {
- currentAction++;
- actions[currentAction].Create(startAction);
- maxAction = currentAction;
- }
- }
+ uh.EndUndoAction();
}
void CellBuffer::DeleteUndoHistory() {
- for (int i = 1; i < maxAction; i++)
- actions[i].Destroy();
- maxAction = 0;
- currentAction = 0;
- savePoint = 0;
+ uh.DeleteUndoHistory();
}
bool CellBuffer::CanUndo() {
- return (!readOnly) && ((currentAction > 0) && (maxAction > 0));
+ return (!readOnly) && (uh.CanUndo());
}
int CellBuffer::StartUndo() {
- // Drop any trailing startAction
- if (actions[currentAction].at == startAction && currentAction > 0)
- currentAction--;
-
- // Count the steps in this action
- int act = currentAction;
- while (actions[act].at != startAction && act > 0) {
- act--;
- }
- return currentAction - act;
+ return uh.StartUndo();
}
const Action &CellBuffer::UndoStep() {
- const Action &actionStep = actions[currentAction];
+ const Action &actionStep = uh.UndoStep();
if (actionStep.at == insertAction) {
BasicDeleteChars(actionStep.position, actionStep.lenData*2);
} else if (actionStep.at == removeAction) {
@@ -874,29 +959,19 @@ const Action &CellBuffer::UndoStep() {
BasicInsertString(actionStep.position, styledData, actionStep.lenData*2);
delete []styledData;
}
- currentAction--;
return actionStep;
}
bool CellBuffer::CanRedo() {
- return (!readOnly) && (maxAction > currentAction);
+ return (!readOnly) && (uh.CanRedo());
}
int CellBuffer::StartRedo() {
- // Drop any leading startAction
- if (actions[currentAction].at == startAction && currentAction < maxAction)
- currentAction++;
-
- // Count the steps in this action
- int act = currentAction;
- while (actions[act].at != startAction && act < maxAction) {
- act++;
- }
- return act - currentAction;
+ return uh.StartRedo();
}
const Action &CellBuffer::RedoStep() {
- const Action &actionStep = actions[currentAction];
+ const Action &actionStep = uh.RedoStep();
if (actionStep.at == insertAction) {
char *styledData = new char[actionStep.lenData * 2];
for (int i = 0; i < actionStep.lenData; i++) {
@@ -908,7 +983,6 @@ const Action &CellBuffer::RedoStep() {
} else if (actionStep.at == removeAction) {
BasicDeleteChars(actionStep.position, actionStep.lenData*2);
}
- currentAction++;
return actionStep;
}
diff --git a/src/CellBuffer.h b/src/CellBuffer.h
index 5fbe2ea8a..6e052077e 100644
--- a/src/CellBuffer.h
+++ b/src/CellBuffer.h
@@ -89,6 +89,42 @@ public:
enum undoCollectionType { undoCollectNone, undoCollectAutoStart, undoCollectManualStart };
+class UndoHistory {
+ Action *actions;
+ int lenActions;
+ int maxAction;
+ int currentAction;
+ int undoSequenceDepth;
+ int savePoint;
+
+ void EnsureUndoRoom();
+
+public:
+ UndoHistory();
+ ~UndoHistory();
+
+ void AppendAction(actionType at, int position, char *data, int length);
+
+ void BeginUndoAction();
+ void EndUndoAction();
+ void DropUndoSequence();
+ void DeleteUndoHistory();
+
+ // The save point is a marker in the undo stack where the container has stated that
+ // the buffer was saved. Undo and redo can move over the save point.
+ void SetSavePoint();
+ bool IsSavePoint() const;
+
+ // To perform an undo, StartUndo is called to retrieve the number of steps, then UndoStep is
+ // called that many times. Similarly for redo.
+ bool CanUndo() const;
+ int StartUndo();
+ const Action &UndoStep();
+ bool CanRedo() const;
+ int StartRedo();
+ const Action &RedoStep();
+};
+
// Holder for an expandable array of characters that supports undo and line markers
// Based on article "Data Structures in a Bit-Mapped Text Editor"
// by Wilfred J. Hansen, Byte January 1987, page 183
@@ -102,13 +138,8 @@ private:
char *part2body;
bool readOnly;
- Action *actions;
- int lenActions;
- int maxAction;
- int currentAction;
undoCollectionType collectingUndo;
- int undoSequenceDepth;
- int savePoint;
+ UndoHistory uh;
LineVector lv;
@@ -117,9 +148,6 @@ private:
void GapTo(int position);
void RoomFor(int insertionLength);
- void EnsureUndoRoom();
- void AppendAction(actionType at, int position, char *data, int length);
-
inline char ByteAt(int position);
void SetByteAt(int position, char ch);
@@ -170,12 +198,11 @@ public:
undoCollectionType SetUndoCollection(undoCollectionType collectUndo);
bool IsCollectingUndo();
- void AppendUndoStartAction();
void BeginUndoAction();
void EndUndoAction();
void DeleteUndoHistory();
- // To perform an undo, StartUndo is called to retreive the number of steps, then UndoStep is
+ // To perform an undo, StartUndo is called to retrieve the number of steps, then UndoStep is
// called that many times. Similarly for redo.
bool CanUndo();
int StartUndo();
diff --git a/src/Document.cxx b/src/Document.cxx
index b50b9691a..bfb52d36e 100644
--- a/src/Document.cxx
+++ b/src/Document.cxx
@@ -94,22 +94,25 @@ int Document::LineStart(int line) {
return cb.LineStart(line);
}
-int Document::LineFromPosition(int pos) {
- return cb.LineFromPosition(pos);
-}
-
-int Document::LineEndPosition(int position) {
- int line = LineFromPosition(position);
+int Document::LineEnd(int line) {
if (line == LinesTotal() - 1) {
- position = LineStart(line + 1);
+ return LineStart(line + 1);
} else {
- position = LineStart(line + 1) - 1;
+ int position = LineStart(line + 1) - 1;
// When line terminator is CR+LF, may need to go back one more
if ((position > LineStart(line)) && (cb.CharAt(position - 1) == '\r')) {
position--;
}
+ return position;
}
- return position;
+}
+
+int Document::LineFromPosition(int pos) {
+ return cb.LineFromPosition(pos);
+}
+
+int Document::LineEndPosition(int position) {
+ return LineEnd(LineFromPosition(position));
}
int Document::VCHomePosition(int position) {
@@ -335,6 +338,7 @@ int Document::Undo() {
enteredCount++;
bool startSavePoint = cb.IsSavePoint();
int steps = cb.StartUndo();
+ Platform::DebugPrintf("Steps=%d\n", steps);
for (int step=0; step<steps; step++) {
int prevLinesTotal = LinesTotal();
const Action &action = cb.UndoStep();
@@ -345,9 +349,11 @@ int Document::Undo() {
int modFlags = SC_PERFORMED_UNDO;
// With undo, an insertion action becomes a deletion notification
if (action.at == removeAction) {
+ Platform::DebugPrintf("Insert of %d\n", action.lenData);
newPos += action.lenData;
modFlags |= SC_MOD_INSERTTEXT;
} else {
+ Platform::DebugPrintf("Remove of %d\n", action.lenData);
modFlags |= SC_MOD_DELETETEXT;
}
if (step == steps-1)
@@ -423,6 +429,11 @@ void Document::InsertString(int position, const char *s, int insertLength) {
}
}
+void Document::ChangeChar(int pos, char ch) {
+ DeleteChars(pos, 1);
+ InsertChar(pos, ch);
+}
+
void Document::DelChar(int pos) {
if (IsCrLf(pos)) {
DeleteChars(pos, 2);
@@ -633,6 +644,25 @@ int Document::LinesTotal() {
return cb.Lines();
}
+void Document::ChangeCase(Range r, bool makeUpperCase) {
+ for (int pos=r.start; pos<r.end; pos++) {
+ char ch = CharAt(pos);
+ if (dbcsCodePage && IsDBCS(pos)) {
+ pos++;
+ } else {
+ if (makeUpperCase) {
+ if (islower(ch)) {
+ ChangeChar(pos, toupper(ch));
+ }
+ } else {
+ if (isupper(ch)) {
+ ChangeChar(pos, tolower(ch));
+ }
+ }
+ }
+ }
+}
+
void Document::SetWordChars(unsigned char *chars) {
int ch;
for (ch = 0; ch < 256; ch++) {
diff --git a/src/Document.h b/src/Document.h
index 59215c75a..4c212b7bd 100644
--- a/src/Document.h
+++ b/src/Document.h
@@ -111,7 +111,6 @@ public:
undoCollectionType SetUndoCollection(undoCollectionType collectUndo) {
return cb.SetUndoCollection(collectUndo);
}
- void AppendUndoStartAction() { cb.AppendUndoStartAction(); }
void BeginUndoAction() { cb.BeginUndoAction(); }
void EndUndoAction() { cb.EndUndoAction(); }
void SetSavePoint();
@@ -123,6 +122,7 @@ public:
void InsertChar(int pos, char ch);
void InsertString(int position, const char *s);
void InsertString(int position, const char *s, int insertLength);
+ void ChangeChar(int pos, char ch);
void DelChar(int pos);
int DelCharBack(int pos);
@@ -138,6 +138,7 @@ public:
void DeleteAllMarks(int markerNum);
int LineFromHandle(int markerHandle) { return cb.LineFromHandle(markerHandle); }
int LineStart(int line);
+ int LineEnd(int line);
int LineEndPosition(int position);
int VCHomePosition(int position);
@@ -154,6 +155,8 @@ public:
long FindText(WORD iMessage,WPARAM wParam,LPARAM lParam);
int LinesTotal();
+ void ChangeCase(Range r, bool makeUpperCase);
+
void SetWordChars(unsigned char *chars);
void SetStylingBits(int bits);
void StartStyling(int position, char mask);
diff --git a/src/Editor.cxx b/src/Editor.cxx
index 8550286ac..226184db2 100644
--- a/src/Editor.cxx
+++ b/src/Editor.cxx
@@ -1700,6 +1700,11 @@ void Editor::NotifyMacroRecord(UINT iMessage, WPARAM wParam, LPARAM lParam) {
case SCI_VCHOMEEXTEND:
case SCI_DELWORDLEFT:
case SCI_DELWORDRIGHT:
+ case SCI_LINECUT:
+ case SCI_LINEDELETE:
+ case SCI_LINETRANSPOSE:
+ case SCI_LOWERCASE:
+ case SCI_UPPERCASE:
break;
// Filter out all others (display changes, etc)
@@ -1735,6 +1740,60 @@ void Editor::PageMove(int direction, bool extend) {
}
}
+void Editor::ChangeCaseOfSelection(bool makeUpperCase) {
+ pdoc->BeginUndoAction();
+ int startCurrent = currentPos;
+ int startAnchor = anchor;
+ if (selType == selRectangle) {
+ int lineStart = pdoc->LineFromPosition(SelectionStart());
+ int lineEnd = pdoc->LineFromPosition(SelectionEnd());
+ for (int line=lineStart; line <= lineEnd; line++) {
+ pdoc->ChangeCase(
+ Range(SelectionStart(line), SelectionEnd(line)),
+ makeUpperCase);
+ }
+ // Would be nicer to keep the rectangular selection but this is complex
+ selType = selStream;
+ SetSelection(startCurrent, startCurrent);
+ } else {
+ pdoc->ChangeCase(Range(SelectionStart(), SelectionEnd()),
+ makeUpperCase);
+ SetSelection(startCurrent, startAnchor);
+ }
+ pdoc->EndUndoAction();
+}
+
+
+void Editor::LineTranspose() {
+ int line = pdoc->LineFromPosition(currentPos);
+ if (line > 0) {
+ int startPrev = pdoc->LineStart(line-1);
+ int endPrev = pdoc->LineEnd(line-1);
+ int start = pdoc->LineStart(line);
+ int end = pdoc->LineEnd(line);
+ int startNext = pdoc->LineStart(line+1);
+ if (end < pdoc->Length()) {
+ end = startNext;
+ char *thisLine = CopyRange(start, end);
+ pdoc->DeleteChars(start, end-start);
+ pdoc->InsertString(startPrev, thisLine, end-start);
+ MovePositionTo(startPrev+end-start);
+ delete []thisLine;
+ } else {
+ // Last line so line has no line end
+ char *thisLine = CopyRange(start, end);
+ char *prevEnd = CopyRange(endPrev, start);
+ pdoc->DeleteChars(endPrev, end-endPrev);
+ pdoc->InsertString(startPrev, thisLine, end-start);
+ pdoc->InsertString(startPrev + end-start, prevEnd, start-endPrev);
+ MovePositionTo(startPrev + end-endPrev);
+ delete []thisLine;
+ delete []prevEnd;
+ }
+
+ }
+}
+
int Editor::KeyCommand(UINT iMessage) {
Point pt = LocationFromPosition(currentPos);
@@ -1910,6 +1969,37 @@ int Editor::KeyCommand(UINT iMessage) {
MovePositionTo(currentPos);
}
break;
+ case SCI_LINECUT: {
+ int lineStart = pdoc->LineFromPosition(currentPos);
+ int lineEnd = pdoc->LineFromPosition(anchor);
+ if (lineStart > lineEnd) {
+ int t = lineEnd;
+ lineEnd = lineStart;
+ lineStart = t;
+ }
+ int start = pdoc->LineStart(lineStart);
+ int end = pdoc->LineStart(lineEnd+1);
+ SetSelection(start,end);
+ Cut();
+ }
+ break;
+ case SCI_LINEDELETE: {
+ int line = pdoc->LineFromPosition(currentPos);
+ int start = pdoc->LineStart(line);
+ int end = pdoc->LineStart(line+1);
+ pdoc->DeleteChars(start, end-start);
+ MovePositionTo(start);
+ }
+ break;
+ case SCI_LINETRANSPOSE:
+ LineTranspose();
+ break;
+ case SCI_LOWERCASE:
+ ChangeCaseOfSelection(false);
+ break;
+ case SCI_UPPERCASE:
+ ChangeCaseOfSelection(true);
+ break;
}
return 0;
}
@@ -3094,7 +3184,8 @@ LRESULT Editor::WndProc(UINT iMessage, WPARAM wParam, LPARAM lParam) {
#ifdef INCLUDE_DEPRECATED_FEATURES
case SCI_APPENDUNDOSTARTACTION:
- pdoc->AppendUndoStartAction();
+ // Not just deprecated - now dead
+ //pdoc->AppendUndoStartAction();
return 0;
#endif
@@ -3649,6 +3740,11 @@ LRESULT Editor::WndProc(UINT iMessage, WPARAM wParam, LPARAM lParam) {
case SCI_ZOOMOUT:
case SCI_DELWORDLEFT:
case SCI_DELWORDRIGHT:
+ case SCI_LINECUT:
+ case SCI_LINEDELETE:
+ case SCI_LINETRANSPOSE:
+ case SCI_LOWERCASE:
+ case SCI_UPPERCASE:
return KeyCommand(iMessage);
case SCI_BRACEHIGHLIGHT:
diff --git a/src/Editor.h b/src/Editor.h
index 16bcd4b22..d1281be5a 100644
--- a/src/Editor.h
+++ b/src/Editor.h
@@ -228,6 +228,8 @@ protected: // ScintillaBase subclass needs access to much of Editor
#endif
void PageMove(int direction, bool extend=false);
+ void ChangeCaseOfSelection(bool makeUpperCase);
+ void LineTranspose();
virtual int KeyCommand(UINT iMessage);
virtual int KeyDefault(int /* key */, int /*modifiers*/);
int KeyDown(int key, bool shift, bool ctrl, bool alt);
diff --git a/src/KeyMap.cxx b/src/KeyMap.cxx
index f339cd275..9ab9694df 100644
--- a/src/KeyMap.cxx
+++ b/src/KeyMap.cxx
@@ -61,36 +61,36 @@ UINT KeyMap::Find(int key, int modifiers) {
}
KeyToCommand KeyMap::MapDefault[] = {
- VK_DOWN, SCI_NORM, SCI_LINEDOWN,
- VK_DOWN, SCI_SHIFT, SCI_LINEDOWNEXTEND,
- VK_UP, SCI_NORM, SCI_LINEUP,
- VK_UP, SCI_SHIFT, SCI_LINEUPEXTEND,
+ VK_DOWN, SCI_NORM, SCI_LINEDOWN,
+ VK_DOWN, SCI_SHIFT, SCI_LINEDOWNEXTEND,
+ VK_UP, SCI_NORM, SCI_LINEUP,
+ VK_UP, SCI_SHIFT, SCI_LINEUPEXTEND,
VK_LEFT, SCI_NORM, SCI_CHARLEFT,
VK_LEFT, SCI_SHIFT, SCI_CHARLEFTEXTEND,
VK_LEFT, SCI_CTRL, SCI_WORDLEFT,
VK_LEFT, SCI_CSHIFT, SCI_WORDLEFTEXTEND,
- VK_RIGHT, SCI_NORM, SCI_CHARRIGHT,
- VK_RIGHT, SCI_SHIFT, SCI_CHARRIGHTEXTEND,
- VK_RIGHT, SCI_CTRL, SCI_WORDRIGHT,
- VK_RIGHT, SCI_CSHIFT, SCI_WORDRIGHTEXTEND,
- VK_HOME, SCI_NORM, SCI_VCHOME,
- VK_HOME, SCI_SHIFT, SCI_VCHOMEEXTEND,
- VK_HOME, SCI_CTRL, SCI_DOCUMENTSTART,
- VK_HOME, SCI_CSHIFT, SCI_DOCUMENTSTARTEXTEND,
+ VK_RIGHT, SCI_NORM, SCI_CHARRIGHT,
+ VK_RIGHT, SCI_SHIFT, SCI_CHARRIGHTEXTEND,
+ VK_RIGHT, SCI_CTRL, SCI_WORDRIGHT,
+ VK_RIGHT, SCI_CSHIFT, SCI_WORDRIGHTEXTEND,
+ VK_HOME, SCI_NORM, SCI_VCHOME,
+ VK_HOME, SCI_SHIFT, SCI_VCHOMEEXTEND,
+ VK_HOME, SCI_CTRL, SCI_DOCUMENTSTART,
+ VK_HOME, SCI_CSHIFT, SCI_DOCUMENTSTARTEXTEND,
VK_END, SCI_NORM, SCI_LINEEND,
VK_END, SCI_SHIFT, SCI_LINEENDEXTEND,
VK_END, SCI_CTRL, SCI_DOCUMENTEND,
VK_END, SCI_CSHIFT, SCI_DOCUMENTENDEXTEND,
- VK_PRIOR, SCI_NORM, SCI_PAGEUP,
- VK_PRIOR, SCI_SHIFT, SCI_PAGEUPEXTEND,
- VK_NEXT, SCI_NORM, SCI_PAGEDOWN,
- VK_NEXT, SCI_SHIFT, SCI_PAGEDOWNEXTEND,
+ VK_PRIOR, SCI_NORM, SCI_PAGEUP,
+ VK_PRIOR, SCI_SHIFT, SCI_PAGEUPEXTEND,
+ VK_NEXT, SCI_NORM, SCI_PAGEDOWN,
+ VK_NEXT, SCI_SHIFT, SCI_PAGEDOWNEXTEND,
VK_DELETE, SCI_NORM, WM_CLEAR,
VK_DELETE, SCI_SHIFT, WM_CUT,
VK_DELETE, SCI_CTRL, SCI_DELWORDRIGHT,
- VK_INSERT, SCI_NORM, SCI_EDITTOGGLEOVERTYPE,
- VK_INSERT, SCI_SHIFT, WM_PASTE,
- VK_INSERT, SCI_CTRL, WM_COPY,
+ VK_INSERT, SCI_NORM, SCI_EDITTOGGLEOVERTYPE,
+ VK_INSERT, SCI_SHIFT, WM_PASTE,
+ VK_INSERT, SCI_CTRL, WM_COPY,
VK_ESCAPE, SCI_NORM, SCI_CANCEL,
VK_BACK, SCI_NORM, SCI_DELETEBACK,
VK_BACK, SCI_CTRL, SCI_DELWORDLEFT,
@@ -103,9 +103,14 @@ KeyToCommand KeyMap::MapDefault[] = {
VK_TAB, SCI_NORM, SCI_TAB,
VK_TAB, SCI_SHIFT, SCI_BACKTAB,
VK_RETURN, SCI_NORM, SCI_NEWLINE,
- 'L', SCI_CTRL, SCI_FORMFEED,
VK_ADD, SCI_CTRL, SCI_ZOOMIN,
VK_SUBTRACT, SCI_CTRL, SCI_ZOOMOUT,
+ //'L', SCI_CTRL, SCI_FORMFEED,
+ 'L', SCI_CTRL, SCI_LINECUT,
+ 'L', SCI_CSHIFT, SCI_LINEDELETE,
+ 'T', SCI_CTRL, SCI_LINETRANSPOSE,
+ 'U', SCI_CTRL, SCI_LOWERCASE,
+ 'U', SCI_CSHIFT, SCI_UPPERCASE,
0,0,0,
};
diff --git a/src/KeyMap.h b/src/KeyMap.h
index 814f3aa3b..bc435e197 100644
--- a/src/KeyMap.h
+++ b/src/KeyMap.h
@@ -11,6 +11,7 @@
#define SCI_CTRL LEFT_CTRL_PRESSED
#define SCI_ALT LEFT_ALT_PRESSED
#define SCI_CSHIFT (SCI_CTRL | SCI_SHIFT)
+#define SCI_ASHIFT (SCI_ALT | SCI_SHIFT)
class KeyToCommand {
public:
diff --git a/src/LexCPP.cxx b/src/LexCPP.cxx
index c6d56702e..4afae231f 100644
--- a/src/LexCPP.cxx
+++ b/src/LexCPP.cxx
@@ -17,9 +17,10 @@
#include "Scintilla.h"
#include "SciLexer.h"
-static void classifyWordCpp(unsigned int start, unsigned int end, WordList &keywords, StylingContext &styler) {
+static bool classifyWordCpp(unsigned int start, unsigned int end, WordList &keywords, StylingContext &styler) {
char s[100];
bool wordIsNumber = isdigit(styler[start]) || (styler[start] == '.');
+ bool wordIsUUID = false;
for (unsigned int i = 0; i < end - start + 1 && i < 30; i++) {
s[i] = styler[start + i];
s[i + 1] = '\0';
@@ -28,10 +29,13 @@ static void classifyWordCpp(unsigned int start, unsigned int end, WordList &keyw
if (wordIsNumber)
chAttr = SCE_C_NUMBER;
else {
- if (keywords.InList(s))
+ if (keywords.InList(s)) {
chAttr = SCE_C_WORD;
+ wordIsUUID = strcmp(s, "uuid") == 0;
+ }
}
styler.ColourTo(end, chAttr);
+ return wordIsUUID;
}
static void ColouriseCppDoc(unsigned int startPos, int length, int initStyle, WordList *keywordlists[],
@@ -52,6 +56,7 @@ static void ColouriseCppDoc(unsigned int startPos, int length, int initStyle, Wo
unsigned int lengthDoc = startPos + length;
int visChars = 0;
styler.StartSegment(startPos);
+ bool lastWordWasUUID = false;
for (unsigned int i = startPos; i <= lengthDoc; i++) {
char ch = chNext;
chNext = styler.SafeGetCharAt(i + 1);
@@ -86,7 +91,12 @@ static void ColouriseCppDoc(unsigned int startPos, int length, int initStyle, Wo
if (state == SCE_C_DEFAULT) {
if (iswordstart(ch)) {
styler.ColourTo(i-1, state);
- state = SCE_C_WORD;
+ if (lastWordWasUUID) {
+ state = SCE_C_UUID;
+ lastWordWasUUID = false;
+ } else {
+ state = SCE_C_WORD;
+ }
} else if (ch == '/' && chNext == '*') {
styler.ColourTo(i-1, state);
if (styler.SafeGetCharAt(i + 2) == '*')
@@ -114,7 +124,7 @@ static void ColouriseCppDoc(unsigned int startPos, int length, int initStyle, Wo
}
} else if (state == SCE_C_WORD) {
if (!iswordchar(ch)) {
- classifyWordCpp(styler.GetStartSegment(), i - 1, keywords, styler);
+ lastWordWasUUID = classifyWordCpp(styler.GetStartSegment(), i - 1, keywords, styler);
state = SCE_C_DEFAULT;
if (ch == '/' && chNext == '*') {
if (styler.SafeGetCharAt(i + 2) == '*')
@@ -199,6 +209,11 @@ static void ColouriseCppDoc(unsigned int startPos, int length, int initStyle, Wo
ch = chNext;
chNext = styler.SafeGetCharAt(i + 1);
}
+ } else if (state == SCE_C_UUID) {
+ if (ch == '\r' || ch == '\n' || ch == ')') {
+ styler.ColourTo(i-1, state);
+ state = SCE_C_DEFAULT;
+ }
}
if (state == SCE_C_DEFAULT) { // One of the above succeeded
if (ch == '/' && chNext == '*') {