aboutsummaryrefslogtreecommitdiffstats
path: root/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/Rendering/ColumnRulerRenderer.cs
blob: 62a29dcb1abc9c9515a846432f9774c8e2da2588 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)

using System;
using System.Windows;
using System.Windows.Media;

using Tango.Scripting.Editors.Rendering;
using Tango.Scripting.Editors.Utils;

namespace Tango.Scripting.Editors.Rendering
{
	/// <summary>
	/// Renders a ruler at a certain column.
	/// </summary>
	sealed class ColumnRulerRenderer : IBackgroundRenderer
	{
		Pen pen;
		int column;
		TextView textView;
		
		public static readonly Color DefaultForeground = Colors.LightGray;
		
		public ColumnRulerRenderer(TextView textView)
		{
			if (textView == null)
				throw new ArgumentNullException("textView");
			
			this.pen = new Pen(new SolidColorBrush(DefaultForeground), 1);
			this.pen.Freeze();
			this.textView = textView;
			this.textView.BackgroundRenderers.Add(this);
		}
		
		public KnownLayer Layer {
			get { return KnownLayer.Background; }
		}
		
		public void SetRuler(int column, Pen pen)
		{
			if (this.column != column) {
				this.column = column;
				textView.InvalidateLayer(this.Layer);
			}
			if (this.pen != pen) {
				this.pen = pen;
				textView.InvalidateLayer(this.Layer);
			}
		}
		
		public void Draw(TextView textView, System.Windows.Media.DrawingContext drawingContext)
		{
			if (column < 1) return;
			double offset = textView.WideSpaceWidth * column;
			Size pixelSize = PixelSnapHelpers.GetPixelSize(textView);
			double markerXPos = PixelSnapHelpers.PixelAlign(offset, pixelSize.Width);
			markerXPos -= textView.ScrollOffset.X;
			Point start = new Point(markerXPos, 0);
			Point end = new Point(markerXPos, Math.Max(textView.DocumentHeight, textView.ActualHeight));
			
			drawingContext.DrawLine(pen, start, end);
		}
	}
}
/span>(string input) { this.input = input; this.inputLength = input.Length; } protected bool IsEndOfFile() { return currentLocation == inputLength; } protected bool HasMoreData() { return currentLocation < inputLength; } protected void AssertHasMoreData() { AXmlParser.Assert(HasMoreData(), "Unexpected end of file"); } protected bool TryMoveNext() { if (currentLocation == inputLength) return false; currentLocation++; return true; } protected void Skip(int count) { AXmlParser.Assert(currentLocation + count <= inputLength, "Skipping after the end of file"); currentLocation += count; } protected void GoBack(int oldLocation) { AXmlParser.Assert(oldLocation <= currentLocation, "Trying to move forward"); maxTouchedLocation = Math.Max(maxTouchedLocation, currentLocation); currentLocation = oldLocation; } protected bool TryRead(char c) { if (currentLocation == inputLength) return false; if (input[currentLocation] == c) { currentLocation++; return true; } else { return false; } } protected bool TryReadAnyOf(params char[] c) { if (currentLocation == inputLength) return false; if (c.Contains(input[currentLocation])) { currentLocation++; return true; } else { return false; } } protected bool TryRead(string text) { if (TryPeek(text)) { currentLocation += text.Length; return true; } else { return false; } } protected bool TryPeekPrevious(char c, int back) { if (currentLocation - back == inputLength) return false; if (currentLocation - back < 0 ) return false; return input[currentLocation - back] == c; } protected bool TryPeek(char c) { if (currentLocation == inputLength) return false; return input[currentLocation] == c; } protected bool TryPeekAnyOf(params char[] chars) { if (currentLocation == inputLength) return false; return chars.Contains(input[currentLocation]); } protected bool TryPeek(string text) { if (!TryPeek(text[0])) return false; // Early exit maxTouchedLocation = Math.Max(maxTouchedLocation, currentLocation + (text.Length - 1)); // The following comparison 'touches' the end of file - it does depend on the end being there if (currentLocation + text.Length > inputLength) return false; return input.Substring(currentLocation, text.Length) == text; } protected bool TryPeekWhiteSpace() { if (currentLocation == inputLength) return false; char c = input[currentLocation]; return ((int)c <= 0x20) && (c == ' ' || c == '\t' || c == '\n' || c == '\r'); } // The move functions do not have to move if already at target // The move functions allow 'overriding' of the document length protected bool TryMoveTo(char c) { return TryMoveTo(c, inputLength); } protected bool TryMoveTo(char c, int inputLength) { if (currentLocation == inputLength) return false; int index = input.IndexOf(c, currentLocation, inputLength - currentLocation); if (index != -1) { currentLocation = index; return true; } else { currentLocation = inputLength; return false; } } protected bool TryMoveToAnyOf(params char[] c) { return TryMoveToAnyOf(c, inputLength); } protected bool TryMoveToAnyOf(char[] c, int inputLength) { if (currentLocation == inputLength) return false; int index = input.IndexOfAny(c, currentLocation, inputLength - currentLocation); if (index != -1) { currentLocation = index; return true; } else { currentLocation = inputLength; return false; } } protected bool TryMoveTo(string text) { return TryMoveTo(text, inputLength); } protected bool TryMoveTo(string text, int inputLength) { if (currentLocation == inputLength) return false; int index = input.IndexOf(text, currentLocation, inputLength - currentLocation, StringComparison.Ordinal); if (index != -1) { maxTouchedLocation = index + text.Length - 1; currentLocation = index; return true; } else { currentLocation = inputLength; return false; } } protected bool TryMoveToNonWhiteSpace() { return TryMoveToNonWhiteSpace(inputLength); } protected bool TryMoveToNonWhiteSpace(int inputLength) { while(true) { if (currentLocation == inputLength) return false; // Reject end of file char c = input[currentLocation]; if (((int)c <= 0x20) && (c == ' ' || c == '\t' || c == '\n' || c == '\r')) { currentLocation++; // Accept white-space continue; } else { return true; // Found non-white-space } } } /// <summary> /// Read a name token. /// The following characters are not allowed: /// "" End of file /// " \n\r\t" Whitesapce /// "=\'\"" Attribute value /// "&lt;>/?" Tags /// </summary> /// <returns> True if read at least one character </returns> protected bool TryReadName(out string res) { int start = currentLocation; // Keep reading up to invalid character while(true) { if (currentLocation == inputLength) break; // Reject end of file char c = input[currentLocation]; if (0x41 <= (int)c) { // Accpet from 'A' onwards currentLocation++; continue; } if (c == ' ' || c == '\n' || c == '\r' || c == '\t' || // Reject whitesapce c == '=' || c == '\'' || c == '"' || // Reject attributes c == '<' || c == '>' || c == '/' || c == '?') { // Reject tags break; } else { currentLocation++; continue; // Accept other character } } if (start == currentLocation) { res = string.Empty; return false; } else { res = GetText(start, currentLocation); return true; } } protected string GetText(int start, int end) { AXmlParser.Assert(end <= currentLocation, "Reading ahead of current location"); if (start == inputLength && end == inputLength) { return string.Empty; } else { return GetCachedString(input.Substring(start, end - start)); } } Dictionary<string, string> stringCache = new Dictionary<string, string>(); int stringCacheRequestedCount; int stringCacheRequestedSize; int stringCacheStoredCount; int stringCacheStoredSize; string GetCachedString(string cached) { stringCacheRequestedCount += 1; stringCacheRequestedSize += 8 + 2 * cached.Length; // Do not bother with long strings if (cached.Length > 32) { stringCacheStoredCount += 1; stringCacheStoredSize += 8 + 2 * cached.Length; return cached; } if (stringCache.ContainsKey(cached)) { // Get the instance from the cache instead return stringCache[cached]; } else { // Add to cache stringCacheStoredCount += 1; stringCacheStoredSize += 8 + 2 * cached.Length; stringCache.Add(cached, cached); return cached; } } public void PrintStringCacheStats() { AXmlParser.Log("String cache: Requested {0} ({1} bytes); Actaully stored {2} ({3} bytes); {4}% stored", stringCacheRequestedCount, stringCacheRequestedSize, stringCacheStoredCount, stringCacheStoredSize, stringCacheRequestedSize == 0 ? 0 : stringCacheStoredSize * 100 / stringCacheRequestedSize); } } }