Esempio n. 1
0
void Styler_Syntax::Insert(unsigned int pos, unsigned int length) {
#ifdef __WXDEBUG__
	Verify();

	const unsigned int docLen = m_doc.GetLength();
	wxASSERT(pos >= 0 && pos < docLen);
	wxASSERT(length >= 0 && pos+length <= docLen);
#endif

	// Adjust end
	if (m_syntax_end > pos)	m_syntax_end += length;
	//else return; // Change outside search area

	unsigned int change_start;
	cxLOCKDOC_READ(m_doc)
		change_start = doc.GetLineStart(pos);
	cxENDLOCK

	const unsigned int adj_end = AdjustForInsertion(pos, length, m_topMatches, 0, change_start);

	unsigned int change_end = wxMax(adj_end, pos + length);
	if (!m_lines.IsLineEnd(change_end) || change_end == change_start) {
		change_end = m_lines.GetLineEndFromPos(change_end);
	}

	// After changes we want the lines to be updated with the new height
	m_updateLineHeight = true;

	// In case the change invalidates the whole rest of the doc
	// we don't want to parse it all. There can also come other
	// changes before next redraw, so we set the limit to change_end.
	DoSearch(change_start, change_end, change_end);
	m_updateLineHeight = false;
}
Esempio n. 2
0
void Styler_Syntax::ReInitSpan(span_matcher& sm, unsigned int start, const SearchInfo& si, int rc, int* ovector) {
	if (!sm.HasEndCaptures()) return;

	match_matcher& spanstarter = *sm.GetStartMatcher();

	unsigned int lineStart;
	unsigned int lineEnd;
	unsigned int lineLen;
	vector<char> line; // TODO: make member variable
	const char* ptrLine = NULL;
	bool usingSi;

	// Check if we can reuse current line info
	if (start >= si.lineStart && start < si.lineEnd) {
		usingSi = true;
		lineStart = si.lineStart;
		lineEnd = si.lineEnd;
		lineLen = si.lineLen;
		ptrLine = &*si.line.begin();
	}
	else {
		usingSi = false;
		lineStart = start; // TODO: set to start-of-line
		cxLOCKDOC_READ(m_doc)
			lineEnd = doc.GetLine(lineStart, line);
		cxENDLOCK
		lineLen = lineEnd - lineStart;
		ptrLine = &*line.begin();
	}

	if (!ovector) {
		// Re-search for the starter to get captures
		// (only needed if we are not in a current search)
		pcre* subRe = spanstarter.GetMatchPattern();
		const int OVECCOUNT = 30;
		int ov[OVECCOUNT];
		ovector = ov;
		const int search_options = PCRE_NO_UTF8_CHECK;
		rc = pcre_exec(
			subRe,                // the compiled pattern
			NULL,                 // extra data - if we study the pattern
			ptrLine,              // the subject string
			lineLen,              // the length of the subject
			start - lineStart,    // start at offset in the subject
			search_options,       // options
			ovector,              // output vector for substring information
			OVECCOUNT);           // number of elements in the output vector
	}

	// ReInit span_matcher to get an updated ender
	if (rc > 0) {
		const vector<char>& lineref = (usingSi ? si.line : line);
		sm.ReInit(lineref, ovector, rc);
	}
}
Esempio n. 3
0
bool Styler_Syntax::OnIdle() {
	if (!HaveActiveSyntax()) return false;

	// Extend syntax a bit longer
	if (m_syntax_end < m_doc.GetLength()) {
		// Make sure the extended position is valid and extends to end-of-line
		unsigned int ext = wxMin(m_syntax_end+EXTSIZE, m_doc.GetLength());
		cxLOCKDOC_READ(m_doc)
			ext = doc.GetLineEnd(ext);
		cxENDLOCK

		DoSearch(m_syntax_end, ext, ext);
	}

	return m_syntax_end != m_doc.GetLength(); // true if we want more idle events
}
Esempio n. 4
0
void Styler_Syntax::Delete(unsigned int start_pos, unsigned int end_pos) {
	const unsigned int docLen = m_doc.GetLength();
	wxASSERT(start_pos >= 0 && start_pos <= docLen);

	if (start_pos == end_pos) return;
	wxASSERT(end_pos > start_pos);

	// Check if we have deleted the entire document
	if (docLen == 0) {
		Invalidate();
		return;
	}

	// Adjust end
	unsigned int length = end_pos - start_pos;
	if (m_syntax_end > start_pos) {
		if (m_syntax_end > end_pos) m_syntax_end -= length;
		else m_syntax_end = start_pos;
	}
	else return; // Change after search area, no need to re-search

	unsigned int change_start;
	cxLOCKDOC_READ(m_doc)
		change_start = doc.GetLineStart(start_pos);
	cxENDLOCK

	unsigned int change_end = AdjustForDeletion(start_pos, end_pos, m_topMatches, 0, change_start);

	if (!m_lines.IsLineEnd(change_end) || change_end == change_start) {
		change_end = m_lines.GetLineEndFromPos(change_end);
	}

	// Do a new search starting from end of first match before pos
	if (change_start != m_syntax_end) {
		wxASSERT(change_start < m_syntax_end);

		// After changes we want the lines to be updated with the new height
		m_updateLineHeight = true;

		// In case the change invalidates the whole rest of the doc
		// we don't want to parse it all. There can also come other
		// changes before next redraw, so we set the limit to change_end.
		DoSearch(change_start, change_end, change_end);
		m_updateLineHeight = false;
	}
}
Esempio n. 5
0
unsigned int FixedLine::GetQuickLineWidth(unsigned int startpos, unsigned int endpos) {
	// This function gives a quick approximation of the total width of the line (without breaking).
	// It ignores elements like tabs, bold chars and asian extra-wide chars.
	if (m_isFontFixedWidth) {
		const unsigned int len = endpos - startpos;
		return len * charwidth;
	}

	// Proportional width font
	wxString text;
	cxLOCKDOC_READ(m_doc)
		text = doc.GetTextPart(startpos, endpos);
	cxENDLOCK

	const wxSize extent = dc.GetTextExtent(text);
	return extent.x;
}
Esempio n. 6
0
void Styler_Syntax::DoSearch(unsigned int start, unsigned int end, unsigned int limit) {
	wxASSERT(start >= 0 && start < m_doc.GetLength());
	wxASSERT(end > start && end <= m_doc.GetLength());
	wxASSERT(limit <= m_doc.GetLength());
	wxASSERT(m_topMatches.subMatcher);
	
	// Don't try to parse if there is no valid parser
	if (!m_topMatches.subMatcher) {
		m_syntax_end = m_lines.GetLength();
		return;
	}

	wxLogDebug(wxT("DoSearch %u-%u %u"), start, end, limit);

	// Make sure we don't get gaps in the parsing
	if (start > m_syntax_end) start = m_syntax_end;

	// Initialize SearchInfo
	SearchInfo si;
	si.pos = start;
	si.line_id = m_lines.GetLineFromCharPos(start);
	si.lineStart = m_lines.GetLineStartpos(si.line_id);
	si.lineEnd = m_lines.GetLineEndpos(si.line_id, false);
	cxLOCKDOC_READ(m_doc)
		doc.GetTextPart(si.lineStart, si.lineEnd, si.line);
	cxENDLOCK
	si.lineLen = si.lineEnd - si.lineStart;
	si.changeEnd = end;
	si.limit = limit;
	si.hitLimit = false;
	si.done = false;

	//wxLogDebug(wxT("  si %u-%u-%u,%u"), si.pos,si.line_id, si.lineStart, si.lineEnd);

	// Do the search
	m_syntax_end = Search(m_topMatches, si, 0, m_syntax_end, NULL);

#ifdef __WXDEBUG__
	Verify();
#endif  //__WXDEBUG__
}
Esempio n. 7
0
void Styler_Syntax::Style(StyleRun& sr) {
	if (!HaveActiveSyntax()) return;

	unsigned int sr_end = sr.GetRunEnd();

	// Check if we need to do a new search
	if (sr_end > m_syntax_end) {
		// Make sure the extended position is valid and extends
		// from start-of-line to end-of-line
		unsigned int sr_start;
		cxLOCKDOC_READ(m_doc)
			sr_start = doc.GetLineStart(m_syntax_end);
		cxENDLOCK

		// Extend stylerun to get better search results (round up to whole EXTSIZEs)
		const unsigned int ext = ((sr_end / EXTSIZE) + 1) * EXTSIZE;
		sr_end =  ext < m_lines.GetLength() ? ext : m_lines.GetLength();
		sr_end = m_lines.GetLineEndFromPos(sr_end);

		DoSearch(sr_start, sr_end, sr_end);
	}

	// Apply base style
	if (m_topStyle) {
		const unsigned int start =  sr.GetRunStart();
		const unsigned int end = sr.GetRunEnd();
		if (m_topStyle->foregroundcolor != wxNullColour) sr.SetForegroundColor(start, end, m_topStyle->foregroundcolor);
		if (m_topStyle->backgroundcolor != wxNullColour) {
			sr.SetBackgroundColor(start, end, m_topStyle->backgroundcolor);
			sr.SetExtendBgColor(m_topStyle->backgroundcolor);
		}
		if (m_topStyle->fontflags != wxFONTFLAG_DEFAULT) sr.SetFontStyle(start, end, m_topStyle->fontflags);
	}

	// Style the run
	DoStyle(sr, 0, m_topMatches.matches);
}
Esempio n. 8
0
unsigned int FixedLine::GetQuickLineHeight(unsigned int startpos, unsigned int endpos) {
	wxASSERT(m_wrapMode != cxWRAP_NONE);

	// This function gives a quick (and very rough) approximation of the total height of the line.
	// It ignores elements like tabs, bold chars and asian extra-wide chars.
	if (m_isFontFixedWidth) {
		const unsigned int len = endpos - startpos;
		const unsigned int linewidth = len * charwidth;
		unsigned int breaklines = linewidth / width;
		if (linewidth % width) ++breaklines;

		return breaklines * charheight;
	}

	// Proportional width font
	wxString text;
	cxLOCKDOC_READ(m_doc)
		text = doc.GetTextPart(startpos, endpos);
	cxENDLOCK

	wxArrayInt widths;
	dc.GetPartialTextExtents(text, widths);

	if (widths.Last() <= width) return charheight;

	unsigned int breaklines = 1;
	unsigned int margin = width;

	for (size_t i = 0; i < widths.Count(); ++i) {
		if (widths[i] > (int)margin) {
			++breaklines;
			margin += width;
		}
	}

	return breaklines * charheight;
}
Esempio n. 9
0
unsigned int Styler_Syntax::Search(submatch& submatches, SearchInfo& si, unsigned int scopeStart, unsigned int scopeEnd, stxmatch* scope) {
	const unsigned int adjPos = si.pos - scopeStart;
	//const unsigned int adjEnd = si.changeEnd - scopeStart;

	// Find the first match after or containing start
	stxmatch m(wxEmptyString, NULL, 0, adjPos, 0, 0, NULL);
	auto_vector<stxmatch>& matches = submatches.matches;
	auto_vector<stxmatch>::iterator next_match = lower_bound(matches.begin(), matches.end(), &m, stxmatch_end_less());

	// Check if we are the end scope
	// (if we contain changeEnd and has no submatches containing it)
	bool isEndScope = false;
	if (scopeStart < si.changeEnd && scopeEnd > si.changeEnd) {
		m.end = si.changeEnd - scopeStart;
		auto_vector<stxmatch>::iterator end_match = lower_bound(next_match, matches.end(), &m, stxmatch_end_less());

		// We are only the endscope if changeEnd is free and there is no open span
		// bordering up to it.
		if (end_match == matches.end() || (*end_match)->start >= m.end ||
			((*end_match)->end == m.end && (!(*end_match)->subMatch.get() || (*end_match)->subMatch->flags & cxSPAN_IS_CLOSED)))
		{
			isEndScope = true;
		}
	}

	// Check if we should enter and search inside match
	if (next_match != matches.end()) {
		// In spans with contentName, we have to enter the content
		if (scope && scope->subMatch->flags & cxSPAN_HAS_CONTENT) {
			if (scope->subMatch->flags & cxSPAN_HAS_STARTER && next_match == matches.begin() && (*next_match)->end == adjPos)
			{
				++next_match;
				wxASSERT(next_match != matches.end()); // content span has been deleted
			}

			// Verify that we are in starter, middle or ender
			wxASSERT(next_match == matches.begin() || (*next_match)->subMatch->flags & cxSPAN_IS_CONTENT || matches.size() == 3); // in ender
		}

		stxmatch* m = *next_match;
		const bool isSpan = m->subMatch.get() && m->subMatch->subMatcher;

		// Pos will always point to start-of-line or end of a match, so if pos
		// is contained in a match it has to be a span which we have to enter.
		if (isSpan) {
			const bool isContentSpan = (m->subMatch->flags & cxSPAN_IS_CONTENT) != 0;

			if (m->start < adjPos || (isContentSpan && m->start == adjPos)) {
				const bool spanClosed = m->subMatch->flags & cxSPAN_IS_CLOSED;

				if (spanClosed && m->end == adjPos) {
					// Don't enter closed matches if we are at end-of-match
					++next_match;
				}
				else {
					const unsigned int subScopeStart = scopeStart + m->start;

					// Re-init span (content spans have been reinited by parent)
					if (!(m->subMatch->flags & cxSPAN_IS_CONTENT)) {
						ReInitSpan(*((span_matcher*)m->subMatch->subMatcher), subScopeStart, si);
					}

					// Search inside span
					m->end = Search(*m->subMatch, si, subScopeStart, scopeStart + m->end, m) - scopeStart;

					// Delete any following matches we might have overwritten
					auto_vector<stxmatch>::iterator p = next_match+1;
					while ( p != matches.end() && m->end > (*p)->start) {
						p = matches.erase(p); // remove overlapped match
					}

					next_match = p;
				}
			}
			else if (m->end == adjPos) ++next_match;
		}
		else if (m->end == adjPos) ++next_match;
	}

	// Search related vars
	static const int OVECCOUNT = 30;
	int ovector[OVECCOUNT];
	int zeromatch = -1; // avoid looping on zero-length matches

	// Get matcher
	matcher& subMatcher = *submatches.subMatcher;
	if (!subMatcher.IsInitialized()) subMatcher.Init();

	// Search from start until we hit a previous match (or end)
	for(;;) {
		// Check if we can end search
		// 1. At end of last changed line and still in same scope.
		// 2. Hit limit
		if (si.done) return wxMax(scopeEnd, si.pos);

		// The syntax highlighting may have changed the height of
		// the line, so if we are done with line, update it.
		/*if (m_updateLineHeight && si.pos == si.lineEnd) {
			if (m_syntax_end < si.lineEnd) m_syntax_end = si.lineEnd; // avoid search loop
			m_lines.UpdateParsedLine(si.line_id);
		}*/

		// Check if we can end this search
		if (!si.hitLimit && isEndScope && (si.pos == si.changeEnd)) {
			si.done = true;
			return wxMax(scopeEnd, si.pos);
		}
		else if (si.pos >= si.limit) {
			// If we hit limit before closing a span we have to keep it open
			// and remove all following matches
			si.hitLimit = true;
			submatches.flags &= ~cxSPAN_IS_CLOSED;
			if (next_match != matches.end()) matches.erase(next_match, matches.end());
			return si.limit;
		}
		else if (si.pos == si.lineEnd) {
			// Advance to next line
			++si.line_id;
			si.lineStart = si.lineEnd;
			si.lineEnd = m_lines.GetLineEndpos(si.line_id, false);
			cxLOCKDOC_READ(m_doc)
				doc.GetTextPart(si.lineStart, si.lineEnd, si.line);
			cxENDLOCK
			si.lineLen = si.lineEnd - si.lineStart;
			zeromatch = -1;
		}

		// Do the search
		const unsigned int offset = si.pos - si.lineStart;
		unsigned int callout_id;
		const int rc = subMatcher.Match(&*si.line.begin(), offset, si.lineLen, callout_id, ovector, OVECCOUNT, zeromatch);
		zeromatch = -1;

		if (rc < 0) {
			// Remove any old matches between pos and end-of-line
			while (next_match != matches.end() && scopeStart + (*next_match)->start < si.lineEnd)
				next_match = matches.erase(next_match);

			if (rc == PCRE_ERROR_NULL) {
				// Invalid pattern
				si.done = true;
				return si.limit;
			}

			// Go to end-of-line
			si.pos = si.lineEnd;
			continue;
		}
		else {
			// Get match interval
			const unsigned int callout_start = si.lineStart + ovector[0]; 
			const unsigned int callout_end = si.lineStart + ovector[1];

			// Move pos to end of match
			si.pos = callout_end;

			// Only span start & end is allowed to be an empty match
			// otherwise we have to move one char ahead to avoid eternal loop
			/*if (callout_start == callout_end && !(subMatcher.IsSpanStart(callout_id) || subMatcher.IsSpanEnd(callout_id))) {
				wxASSERT(false);
				++si.pos;
				continue;
			}*/

			const bool isSpanStart = subMatcher.IsSpanStart(callout_id);
			matcher& m = subMatcher.GetCallout(callout_id);
			const unsigned int matchStart = callout_start - scopeStart;
			const unsigned int matchEnd =  si.pos - scopeStart;

			// Check if we have start overlapping with following match
			if (next_match != matches.end() && callout_start == scopeStart + (*next_match)->start) {
				// If we are both spans and the starters seem equivalent
				// we just enter and continue
				stxmatch& sm = *(*next_match);
				if (isSpanStart && sm.m_matcher == &m) {
					auto_vector<stxmatch>& submatches = sm.subMatch->matches;
					if (!submatches.empty()) {
						const stxmatch* starter = submatches[0];
						if (starter->start == 0 && starter->end == matchEnd-matchStart) {

							ReInitSpan(*((span_matcher*)sm.subMatch->subMatcher), callout_start, si);
							sm.end = Search(*sm.subMatch, si, callout_start, scopeStart + sm.end, *next_match) - scopeStart;
							++next_match;

							// Check if we have overwritten following matches
							while (next_match != matches.end() && si.pos > scopeStart + (*next_match)->start)
								next_match = matches.erase(next_match);

							continue;
						}
					}
				}
			}

			const bool isSpanEnd = subMatcher.IsSpanEnd(callout_id);

			if (callout_start != callout_end || isSpanStart) {
				if (isSpanEnd && submatches.flags & cxSPAN_IS_CONTENT) {
					// If we are in a content span, the ender belongs to the parent
					// So we ignore it and let the parent find it.
					si.pos = callout_start;
				}
				else {
					// Create the new match
					auto_ptr<stxmatch> iv(new stxmatch(m.GetName(), &m, matchStart, matchEnd, NULL, NULL, scope));

					// Style It
					iv->st = GetStyle(*iv);

					// Check if the match is span or has any captures
					if (isSpanStart) {
						CreateSpan(callout_start, callout_end, subMatcher, callout_id, si, iv.get(), rc, ovector);
						iv->end = si.pos - scopeStart;

						// Avoid eternal loop with zero-length spans
						if (iv->start == iv->end) zeromatch = callout_id;
					}
					else if (m.HasCaptures()) {
						AddCaptures(m, *iv, scopeStart, si, rc, ovector);
					}

					// Add new match to list
					next_match = matches.insert(next_match, iv);
					++next_match;

					if (isSpanEnd) submatches.flags |= cxSPAN_HAS_ENDER;
				}
			}

			// Check if we can close the span
			if (isSpanEnd) {
				// Close span
				submatches.flags |= cxSPAN_IS_CLOSED;

				// Remove any leftover matches
				if (next_match != matches.end())
					matches.erase(next_match, matches.end());

				return si.pos;
			}
			else {
				// Check if we have overwritten following matches
				while (next_match != matches.end() && si.pos > scopeStart + (*next_match)->start)
					next_match = matches.erase(next_match);
			}

			// Avoid eternal loop with faulty regexs
			if (callout_start == callout_end && callout_end == si.pos)
				zeromatch = callout_id;
		}
	}
}
Esempio n. 10
0
void Styler_Syntax::XmlText(unsigned int offset, const submatch& sm, unsigned int start, unsigned int end, vector<char>& text) const {
	unsigned int textstart = start;

	for (auto_vector<stxmatch>::const_iterator p = sm.matches.begin(); p != sm.matches.end(); ++p) {
		const stxmatch& m = *(*p);

		// Check if there is overlap
		if (m.end <= start) continue;
		if (m.start >= m.end) break;
		const unsigned int matchstart = wxMax(start, m.start);
		const unsigned int matchend = wxMin(end, m.end);

		// Print text before submatch
		if (textstart < matchstart) {
			const unsigned int len = matchstart - textstart;
			text.resize(text.size() + len);
			cxLOCKDOC_READ(m_doc)
				doc.GetTextPart(offset + textstart, offset + matchstart, (unsigned char*)(&*text.end() - len));
			cxENDLOCK
		}

		// Start tag
		const wxCharBuffer name = m.m_name.mb_str();
		const size_t len = strlen(name.data());
		if (len) {
			text.push_back('<');
			text.insert(text.end(), name.data(), name.data() + len);
			text.push_back('>');
		}

		// Subscopes
		if (m.subMatch.get()) {
			XmlText(offset + m.start, *m.subMatch, matchstart - m.start, matchend - m.start, text);
		}
		else {
			// Print text contained in submatch
			if (matchstart < matchend) {
				const unsigned int len = matchend - matchstart;
				text.resize(text.size() + len);
				cxLOCKDOC_READ(m_doc)
					doc.GetTextPart(offset + matchstart, offset + matchend, (unsigned char*)(&*text.end() - len));
				cxENDLOCK
			}
		}

		// End tag
		if (len) {
			text.push_back('<');
			text.push_back('/');
			text.insert(text.end(), name.data(), name.data() + len);
			text.push_back('>');
		}

		textstart = matchend;
	}

	// Print text after last submatch
	if (textstart < end) {
		const unsigned int len = end - textstart;
		text.resize(text.size() + len);
		cxLOCKDOC_READ(m_doc)
			doc.GetTextPart(offset + textstart, offset + end, (unsigned char*)(&*text.end() - len));
		cxENDLOCK
	}
}
Esempio n. 11
0
void Styler_SearchHL::Style(StyleRun& sr) {
	const unsigned int rstart =  sr.GetRunStart();
	const unsigned int rend = sr.GetRunEnd();

	// Style the run with search ranges
	for (vector<interval>::const_iterator r = m_searchRanges.begin(); r != m_searchRanges.end(); ++r) {
		if (r->end > rstart && r->start < rend) {
			unsigned int start = wxMax(rstart, r->start);
			unsigned int end   = wxMin(rend, r->end);
			sr.SetBackgroundColor(start, end, m_rangeColor);
		}
	}

	// No need for more styling if no search text
	if (m_text.empty()) return;

	// Extend stylerun start/end to get better search results (round up to whole EXTSIZEs)
	unsigned int sr_start = rstart> 100 ? rstart - 100 : 0;
	const unsigned int ext_end = ((rend/EXTSIZE) * EXTSIZE) + EXTSIZE;
	unsigned int sr_end = ext_end < m_lines.GetLength() ? ext_end : m_lines.GetLength();

	// Make sure the extended positions are valid
	cxLOCKDOC_READ(m_doc)
		sr_start = doc.GetValidCharPos(sr_start);
		if (sr_end != m_lines.GetLength()) sr_end = doc.GetValidCharPos(sr_end);
	cxENDLOCK

	//wxLogDebug("Style %u %u", rstart, rend);
	//wxLogDebug(" %u %u - %u %u", sr_start, sr_end, m_search_start, m_search_end);
	// Check if we need to do a new search
	if (sr_start < m_search_start || m_search_end < sr_end) {
		// Check if there is overlap so we can just extend the search area
		if (sr_end > m_search_start && sr_start < m_search_end) {
			sr_start = wxMin(sr_start, m_search_start);
			sr_end = wxMax(sr_end, m_search_end);
		}
		else {
			// Else we have to move it
			m_matches.clear();
			m_search_start = 0;
			m_search_end = 0;
		}

		// Do the search
		if (sr_start < m_search_start) {
			// Search from top
			DoSearch(sr_start, sr_end);
		}
		else if (sr_end > m_search_end) {
			// Search from bottom
			DoSearch(sr_start, sr_end, true);
		}
		else wxASSERT(false);

		m_search_start = sr_start;
		m_search_end = sr_end;
	}

	// Style the run with matches
	for (vector<interval>::iterator p = m_matches.begin(); p != m_matches.end(); ++p) {
		if (p->start > rend) break;

		// Check for overlap (or zero-length sel at start-of-line)
		if ((p->end > rstart && p->start < rend) || (p->start == p->end && p->end == rstart)) {
			unsigned int start = wxMax(rstart, p->start);
			unsigned int end   = wxMin(rend, p->end);

			// Only draw it if it is in range
			if (!m_searchRanges.empty()) {
				bool inRange = false;
				for (vector<interval>::const_iterator s = m_searchRanges.begin(); s != m_searchRanges.end(); ++s) {
					if (start >= s->start && start < s->end) {
						inRange = true;
						break;
					}
				}
				if (!inRange) continue;
			}
			
			ApplyStyle(sr, start, end);
		}
	}
}
Esempio n. 12
0
unsigned int FixedLine::SetLine(unsigned int startpos, unsigned int endpos, bool cache) {
	m_docLen = m_doc.GetLength();

#ifdef __WXDEBUG__
	wxASSERT(!m_inSetLine); // re-entrancy check
	m_inSetLine = true;

	wxASSERT(startpos >= 0 && startpos < m_docLen);
	wxASSERT(endpos > startpos && endpos <= m_docLen);

	if (startpos > 0) {
		wxChar c;
		cxLOCKDOC_READ(m_doc)
			c = doc.GetChar(startpos - 1);
		cxENDLOCK
		wxASSERT(c == wxT('\n'));
	}
	if (endpos < m_docLen) {
		wxChar c;
		cxLOCKDOC_READ(m_doc)
			c = doc.GetChar(endpos - 1);
		cxENDLOCK
		wxASSERT(c == wxT('\n'));
	}
#endif

	if (!cache || startpos != textstart || endpos != textend) {
		textstart = startpos;
		textend = endpos;
		m_lineLen = endpos - startpos;

		// Check if we need to resize line buffer
		if (m_lineBufferLen < m_lineLen) {
			m_lineBufferLen = m_lineLen;
			m_lineBuffer = wxCharBuffer(m_lineBufferLen); // wxCharBuffer allocs room for & adds nullbyte at len
		}

		// Cache the current line in lineBuffer (as UTF-8)
		cxLOCKDOC_READ(m_doc)
			doc.GetTextPart(textstart, textend, (unsigned char*)m_lineBuffer.data());
		cxENDLOCK

		// Style the lines
		m_sr.Init(textstart, textend);
		for (vector<Styler*>::iterator si = m_stylers.begin(); si != m_stylers.end(); ++si) {
			(*si)->Style(m_sr);
		}

		m_extents.clear();
		m_extents.reserve(m_lineLen);
		unsigned int xpos = 0;
		unsigned int lastpos = 0;
		unsigned int style_start = 0;
		int fontStyle = m_sr.GetFontStyle(0);
		char* dbi = m_lineBuffer.data();

		// Build list of text extends (totalling) compensating for tabs and styles
		// There is one extent per byte in the text. In utf8 chars composed out of multiple
		// bytes, they will all have same value.
		for (unsigned int style_id = 0; style_id < m_sr.GetStyleCount(); ++style_id) {
			const unsigned int style_end = m_sr.GetStyleEnd(style_id) - textstart;

			// Ignore zero length styles
			if (style_start == style_end) continue;

			// Check for style change
			if (m_sr.GetFontStyle(style_id) != fontStyle) {
				if (style_start > lastpos) {
					m_sr.ApplyFontStyle(fontStyle);

					// Get extends for current segment
					m_extsBuf.clear();
					const unsigned int seg_len = style_start-lastpos;
					const wxString text(dbi+lastpos, wxConvUTF8, seg_len);
					dc.GetPartialTextExtents(text, m_extsBuf);
					wxASSERT(!text.empty() && m_extsBuf.size() == text.size());

					// Add to main list adjusted for offset
					unsigned int extpos = 0;
					unsigned int offset = xpos;
					for (unsigned int i = lastpos; i < style_start; ++i) {
						if ((dbi[i] & 0xC0) == 0x80) m_extents.push_back(xpos); // Only count first byte of UTF-8 multibyte chars
						else if (dbi[i] == '\t') {
							// Add tab extend
							xpos = ((xpos / tabwidth)+1) * tabwidth; // GetTabPoint(xpos);
							offset += xpos - (m_extsBuf[extpos] + offset);
							m_extents.push_back(xpos);
							++extpos;
						}
						else {
							xpos = m_extsBuf[extpos] + offset;
							m_extents.push_back(xpos);
							++extpos;
						}
					}

					// Small hack to make lines that end with italics not cut off the edge of the last character
					if (fontStyle &= wxFONTFLAG_ITALIC) {
						m_extents.back() += 2;
						xpos = m_extents.back();
					}
				}

				lastpos = style_start;
				fontStyle = m_sr.GetFontStyle(style_id);
			}

			style_start = style_end;
		}

		// Add extends for last segment
		if (lastpos < m_lineLen) {
			m_sr.ApplyFontStyle(fontStyle);

			// Get extends for current segment
			m_extsBuf.clear();
			const unsigned int seg_len = m_lineLen-lastpos;
			const wxString text(dbi+lastpos, wxConvUTF8, seg_len);
			dc.GetPartialTextExtents(text, m_extsBuf);
			wxASSERT(!text.empty() && m_extsBuf.size() == text.size());

			// Add to main list adjusted for offset
			unsigned int extpos = 0;
			unsigned int offset = xpos;
			for (unsigned int i = lastpos; i < m_lineLen; ++i) {
				if ((dbi[i] & 0xC0) == 0x80) m_extents.push_back(xpos); // Only count first byte of UTF-8 multibyte chars
				else if (dbi[i] == '\t') {
					// Add tab extend
					xpos = ((xpos / tabwidth)+1) * tabwidth; // GetTabPoint(xpos);
					offset += xpos - (m_extsBuf[extpos] + offset);
					m_extents.push_back(xpos);
					++extpos;
				}
				else {
					xpos = m_extsBuf[extpos] + offset;
					m_extents.push_back(xpos);
					++extpos;
				}
			}
		}

		wxASSERT(m_extents.size() == m_lineLen);
		BreakLine();
	}
	else if (width != old_width) {
		wxASSERT(m_extents.size() == m_lineLen);
		BreakLine();
	}

#ifdef __WXDEBUG__
	m_inSetLine = false; // re-entrancy check
#endif

	return (m_wrapMode == cxWRAP_NONE) ? m_lineWidth : height;
}
Esempio n. 13
0
void DocHistory::ReBuildTree() {
	if (m_document_id == -1) {
		wxASSERT(m_sourceDoc.IsDraft());
		// The draft has no parent (and can't have children)
		// So just add a single entry.
		m_items.clear();
		m_positions.clear();

		item new_item;
		new_item.doc = m_sourceDoc;
		cxLOCKDOC_READ(m_doc)
			new_item.date = doc.GetDate();
		cxENDLOCK
		new_item.parent = 0; // root is it's own parent
		new_item.ypos = 0;

		m_items.push_back(new_item);
		m_positions.push_back(0);
		m_selectedNode = 0;

		// Update timeline
		m_pTimeline->Clear();
		m_pTimeline->AddItem(new_item.date);

		// Update the VersionTree
		m_pTree->Clear();
		m_pTree->AddRoot();
	}
	else
	{
		m_items.clear();
		m_positions.clear();

		// Add the root
		const doc_id root(DOCUMENT, m_document_id, 0); // root is always zero
		item new_item;
		new_item.doc = root;
		cxLOCK_READ(m_catalyst)
			new_item.date = catalyst.GetDocDate(root);
			new_item.parent = 0; // root is it's own parent
			new_item.ypos = 0;
			m_items.push_back(new_item);
			if (m_sourceDoc == root) m_selectedNode = 0;
			else m_selectedNode = -1; // not yet set

			// Build the tree
			AddChildren(0, root, m_sourceDoc, catalyst);
		cxENDLOCK
		wxASSERT(m_selectedNode >= 0 && m_selectedNode < (int)m_items.size());

		// Update Timeline & VersionTree
		m_pTimeline->Clear();
		m_pTree->Clear();
		if (!m_items.empty()) {
			m_pTimeline->AddItem(new_item.date);
			m_pTree->AddRoot();
		}
		for(unsigned int i = 1; i < m_items.size(); ++i) {
			const int ypos = m_pTimeline->AddItem(m_items[i].date);
			m_pTree->AddNode(m_items[i].parent, ypos);
			m_items[i].ypos = ypos;
		}
	}

	m_pTree->CalculateLayout();

	m_treeHeight = m_items.empty() ? 0 : m_items.back().ypos + m_lineHeight;
}