diff options
author | nyamatongwe <unknown> | 2009-04-12 09:32:53 +0000 |
---|---|---|
committer | nyamatongwe <unknown> | 2009-04-12 09:32:53 +0000 |
commit | 01355323d119b4c7b74d11f5012099813afa3031 (patch) | |
tree | 20390b4aacfaa851b870a4236d2d33bf40f9c65c /src/PerLine.cxx | |
parent | 001550a0de196eca314eea792bfada74a19773b1 (diff) | |
download | scintilla-mirror-01355323d119b4c7b74d11f5012099813afa3031.tar.gz |
Annotations and text margins added.
Diffstat (limited to 'src/PerLine.cxx')
-rw-r--r-- | src/PerLine.cxx | 464 |
1 files changed, 464 insertions, 0 deletions
diff --git a/src/PerLine.cxx b/src/PerLine.cxx new file mode 100644 index 000000000..b90416abb --- /dev/null +++ b/src/PerLine.cxx @@ -0,0 +1,464 @@ +// Scintilla source code edit control +/** @file PerLine.cxx + ** Manages data associated with each line of the document + **/ +// Copyright 1998-2009 by Neil Hodgson <neilh@scintilla.org> +// The License.txt file describes the conditions under which this software may be distributed. + +#include <string.h> + +#include "Platform.h" + +#include "Scintilla.h" +#include "SplitVector.h" +#include "Partitioning.h" +#include "CellBuffer.h" +#include "PerLine.h" + +#ifdef SCI_NAMESPACE +using namespace Scintilla; +#endif + +MarkerHandleSet::MarkerHandleSet() { + root = 0; +} + +MarkerHandleSet::~MarkerHandleSet() { + MarkerHandleNumber *mhn = root; + while (mhn) { + MarkerHandleNumber *mhnToFree = mhn; + mhn = mhn->next; + delete mhnToFree; + } + root = 0; +} + +int MarkerHandleSet::Length() const { + int c = 0; + MarkerHandleNumber *mhn = root; + while (mhn) { + c++; + mhn = mhn->next; + } + return c; +} + +int MarkerHandleSet::NumberFromHandle(int handle) const { + MarkerHandleNumber *mhn = root; + while (mhn) { + if (mhn->handle == handle) { + return mhn->number; + } + mhn = mhn->next; + } + return - 1; +} + +int MarkerHandleSet::MarkValue() const { + unsigned int m = 0; + MarkerHandleNumber *mhn = root; + while (mhn) { + m |= (1 << mhn->number); + mhn = mhn->next; + } + return m; +} + +bool MarkerHandleSet::Contains(int handle) const { + MarkerHandleNumber *mhn = root; + while (mhn) { + if (mhn->handle == handle) { + return true; + } + mhn = mhn->next; + } + return false; +} + +bool MarkerHandleSet::InsertHandle(int handle, int markerNum) { + MarkerHandleNumber *mhn = new MarkerHandleNumber; + if (!mhn) + return false; + mhn->handle = handle; + mhn->number = markerNum; + mhn->next = root; + root = mhn; + return true; +} + +void MarkerHandleSet::RemoveHandle(int handle) { + MarkerHandleNumber **pmhn = &root; + while (*pmhn) { + MarkerHandleNumber *mhn = *pmhn; + if (mhn->handle == handle) { + *pmhn = mhn->next; + delete mhn; + return; + } + pmhn = &((*pmhn)->next); + } +} + +bool MarkerHandleSet::RemoveNumber(int markerNum) { + bool performedDeletion = false; + MarkerHandleNumber **pmhn = &root; + while (*pmhn) { + MarkerHandleNumber *mhn = *pmhn; + if (mhn->number == markerNum) { + *pmhn = mhn->next; + delete mhn; + performedDeletion = true; + } else { + pmhn = &((*pmhn)->next); + } + } + return performedDeletion; +} + +void MarkerHandleSet::CombineWith(MarkerHandleSet *other) { + MarkerHandleNumber **pmhn = &root; + while (*pmhn) { + pmhn = &((*pmhn)->next); + } + *pmhn = other->root; + other->root = 0; +} + +LineMarkers::~LineMarkers() { + for (int line = 0; line < markers.Length(); line++) { + delete markers[line]; + markers[line] = 0; + } + markers.DeleteAll(); +} + +void LineMarkers::InsertLine(int line) { + if (markers.Length()) { + markers.Insert(line, 0); + } +} + +void LineMarkers::RemoveLine(int line) { + // Retain the markers from the deleted line by oring them into the previous line + if (markers.Length()) { + if (line > 0) { + MergeMarkers(line - 1); + } + markers.Delete(line); + } +} + +int LineMarkers::LineFromHandle(int markerHandle) { + if (markers.Length()) { + for (int line = 0; line < markers.Length(); line++) { + if (markers[line]) { + if (markers[line]->Contains(markerHandle)) { + return line; + } + } + } + } + return -1; +} + +void LineMarkers::MergeMarkers(int pos) { + if (markers[pos + 1] != NULL) { + if (markers[pos] == NULL) + markers[pos] = new MarkerHandleSet; + markers[pos]->CombineWith(markers[pos + 1]); + delete markers[pos + 1]; + markers[pos + 1] = NULL; + } +} + +int LineMarkers::MarkValue(int line) { + if (markers.Length() && (line >= 0) && (line < markers.Length()) && markers[line]) + return markers[line]->MarkValue(); + else + return 0; +} + +int LineMarkers::AddMark(int line, int markerNum, int lines) { + handleCurrent++; + if (!markers.Length()) { + // No existing markers so allocate one element per line + markers.InsertValue(0, lines, 0); + } + if (!markers[line]) { + // Need new structure to hold marker handle + markers[line] = new MarkerHandleSet(); + if (!markers[line]) + return - 1; + } + markers[line]->InsertHandle(handleCurrent, markerNum); + + return handleCurrent; +} + +void LineMarkers::DeleteMark(int line, int markerNum, bool all) { + if (markers.Length() && (line >= 0) && (line < markers.Length()) && markers[line]) { + if (markerNum == -1) { + delete markers[line]; + markers[line] = NULL; + } else { + bool performedDeletion = markers[line]->RemoveNumber(markerNum); + while (all && performedDeletion) { + performedDeletion = markers[line]->RemoveNumber(markerNum); + } + if (markers[line]->Length() == 0) { + delete markers[line]; + markers[line] = NULL; + } + } + } +} + +void LineMarkers::DeleteMarkFromHandle(int markerHandle) { + int line = LineFromHandle(markerHandle); + if (line >= 0) { + markers[line]->RemoveHandle(markerHandle); + if (markers[line]->Length() == 0) { + delete markers[line]; + markers[line] = NULL; + } + } +} + +LineLevels::~LineLevels() { +} + +void LineLevels::InsertLine(int line) { + if (levels.Length()) { + int level = SC_FOLDLEVELBASE; + if ((line > 0) && (line < levels.Length())) { + level = levels[line-1] & ~SC_FOLDLEVELWHITEFLAG; + } + levels.InsertValue(line, 1, level); + } +} + +void LineLevels::RemoveLine(int line) { + if (levels.Length()) { + // Move up following lines but merge header flag from this line + // to line before to avoid a temporary disappearence causing expansion. + int firstHeader = levels[line] & SC_FOLDLEVELHEADERFLAG; + levels.Delete(line); + if (line > 0) + levels[line-1] |= firstHeader; + } +} + +void LineLevels::ExpandLevels(int sizeNew) { + levels.InsertValue(levels.Length(), sizeNew - levels.Length(), SC_FOLDLEVELBASE); +} + +void LineLevels::ClearLevels() { + levels.DeleteAll(); +} + +int LineLevels::SetLevel(int line, int level, int lines) { + int prev = 0; + if ((line >= 0) && (line < lines)) { + if (!levels.Length()) { + ExpandLevels(lines + 1); + } + prev = levels[line]; + if (prev != level) { + levels[line] = level; + } + } + return prev; +} + +int LineLevels::GetLevel(int line) { + if (levels.Length() && (line >= 0) && (line < levels.Length())) { + return levels[line]; + } else { + return SC_FOLDLEVELBASE; + } +} + +LineState::~LineState() { +} + +void LineState::InsertLine(int line) { + if (lineStates.Length()) { + lineStates.EnsureLength(line); + lineStates.Insert(line, 0); + } +} + +void LineState::RemoveLine(int line) { + if (lineStates.Length() > line) { + lineStates.Delete(line); + } +} + +int LineState::SetLineState(int line, int state) { + lineStates.EnsureLength(line + 1); + int stateOld = lineStates[line]; + lineStates[line] = state; + return stateOld; +} + +int LineState::GetLineState(int line) { + lineStates.EnsureLength(line + 1); + return lineStates[line]; +} + +int LineState::GetMaxLineState() { + return lineStates.Length(); +} + +static int NumberLines(const char *text) { + if (text) { + int newLines = 0; + while (*text) { + if (*text == '\n') + newLines++; + text++; + } + return newLines+1; + } else { + return 0; + } +} + +// Each allocated LineAnnotation is a char array which starts with an AnnotationHeader +// and then has text and optional styles. + +static const int IndividualStyles = 0x100; + +struct AnnotationHeader { + short style; // Style IndividualStyles implies array of styles + short lines; + int length; +}; + +LineAnnotation::~LineAnnotation() { + ClearAll(); +} + +void LineAnnotation::InsertLine(int line) { + if (annotations.Length()) { + annotations.Insert(line, 0); + } +} + +void LineAnnotation::RemoveLine(int line) { + if (annotations.Length() && (line < annotations.Length())) { + delete []annotations[line]; + annotations.Delete(line); + } +} + +bool LineAnnotation::AnySet() const { + return annotations.Length() > 0; +} + +bool LineAnnotation::MultipleStyles(int line) const { + if (annotations.Length() && (line < annotations.Length()) && annotations[line]) + return reinterpret_cast<AnnotationHeader *>(annotations[line])->style == IndividualStyles; + else + return 0; +} + +int LineAnnotation::Style(int line) { + if (annotations.Length() && (line < annotations.Length()) && annotations[line]) + return reinterpret_cast<AnnotationHeader *>(annotations[line])->style; + else + return 0; +} + +const char *LineAnnotation::Text(int line) const { + if (annotations.Length() && (line < annotations.Length()) && annotations[line]) + return annotations[line]+sizeof(AnnotationHeader); + else + return 0; +} + +const char *LineAnnotation::Styles(int line) const { + if (annotations.Length() && (line < annotations.Length()) && annotations[line] && MultipleStyles(line)) + return annotations[line] + sizeof(AnnotationHeader) + Length(line); + else + return 0; +} + +static char *AllocateAnnotation(int length, int style) { + size_t len = sizeof(AnnotationHeader) + length + ((style == IndividualStyles) ? length : 0); + char *ret = new char[len]; + memset(ret, 0, len); + return ret; +} + +void LineAnnotation::SetText(int line, const char *text) { + if (text) { + annotations.EnsureLength(line+1); + int style = Style(line); + if (annotations[line]) { + delete []annotations[line]; + } + annotations[line] = AllocateAnnotation(strlen(text), style); + AnnotationHeader *pah = reinterpret_cast<AnnotationHeader*>(annotations[line]); + pah->style = static_cast<short>(style); + pah->length = strlen(text); + pah->lines = static_cast<short>(NumberLines(text)); + memcpy(annotations[line]+sizeof(AnnotationHeader), text, pah->length); + } else { + if (annotations.Length() && (line < annotations.Length()) && annotations[line]) { + delete []annotations[line]; + annotations[line] = 0; + } + } +} + +void LineAnnotation::ClearAll() { + for (int line = 0; line < annotations.Length(); line++) { + delete []annotations[line]; + annotations[line] = 0; + } + annotations.DeleteAll(); +} + +void LineAnnotation::SetStyle(int line, int style) { + annotations.EnsureLength(line+1); + if (!annotations[line]) { + annotations[line] = AllocateAnnotation(0, style); + } + reinterpret_cast<AnnotationHeader *>(annotations[line])->style = static_cast<short>(style); +} + +void LineAnnotation::SetStyles(int line, const char *styles) { + annotations.EnsureLength(line+1); + if (!annotations[line]) { + annotations[line] = AllocateAnnotation(0, IndividualStyles); + } else { + AnnotationHeader *pahSource = reinterpret_cast<AnnotationHeader *>(annotations[line]); + if (pahSource->style != IndividualStyles) { + char *allocation = AllocateAnnotation(pahSource->length, IndividualStyles); + AnnotationHeader *pahAlloc = reinterpret_cast<AnnotationHeader *>(allocation); + pahAlloc->length = pahSource->length; + pahAlloc->lines = pahSource->lines; + memcpy(allocation + sizeof(AnnotationHeader), annotations[line] + sizeof(AnnotationHeader), pahSource->length); + delete []annotations[line]; + annotations[line] = allocation; + } + } + AnnotationHeader *pah = reinterpret_cast<AnnotationHeader *>(annotations[line]); + pah->style = IndividualStyles; + memcpy(annotations[line] + sizeof(AnnotationHeader) + pah->length, styles, pah->length); +} + +int LineAnnotation::Length(int line) const { + if (annotations.Length() && (line < annotations.Length()) && annotations[line]) + return reinterpret_cast<AnnotationHeader *>(annotations[line])->length; + else + return 0; +} + +int LineAnnotation::Lines(int line) const { + if (annotations.Length() && (line < annotations.Length()) && annotations[line]) + return reinterpret_cast<AnnotationHeader *>(annotations[line])->lines; + else + return 0; +} |