void CopyData(TextEditorData data, Selection selection) { copiedDocument = null; monoDocument = null; if (selection != null && data != null && data.Document != null) { copiedDocument = new Document(); monoDocument = new Document(); this.docStyle = data.ColorStyle; this.options = data.Options; this.mode = data.Document.SyntaxMode != null && data.Options.EnableSyntaxHighlighting ? data.Document.SyntaxMode : Mono.TextEditor.Highlighting.SyntaxMode.Default; switch (selection.SelectionMode) { case SelectionMode.Normal: isBlockMode = false; ISegment segment = selection.GetSelectionRange(data); copiedDocument.Text = this.mode.GetTextWithoutMarkup(data.Document, data.ColorStyle, segment.Offset, segment.Length); monoDocument.Text = this.mode.GetTextWithoutMarkup(data.Document, data.ColorStyle, segment.Offset, segment.Length); LineSegment line = data.Document.GetLineByOffset(segment.Offset); var spanStack = line.StartSpan.Clone(); SyntaxModeService.ScanSpans(data.Document, this.mode, this.mode, spanStack, line.Offset, segment.Offset); this.copiedDocument.GetLine(DocumentLocation.MinLine).StartSpan = spanStack; break; case SelectionMode.Block: isBlockMode = true; DocumentLocation visStart = data.LogicalToVisualLocation(selection.Anchor); DocumentLocation visEnd = data.LogicalToVisualLocation(selection.Lead); int startCol = System.Math.Min(visStart.Column, visEnd.Column); int endCol = System.Math.Max(visStart.Column, visEnd.Column); for (int lineNr = selection.MinLine; lineNr <= selection.MaxLine; lineNr++) { LineSegment curLine = data.Document.GetLine(lineNr); int col1 = curLine.GetLogicalColumn(data, startCol) - 1; int col2 = System.Math.Min(curLine.GetLogicalColumn(data, endCol) - 1, curLine.EditableLength); if (col1 < col2) { ((IBuffer)copiedDocument).Insert(copiedDocument.Length, data.Document.GetTextAt(curLine.Offset + col1, col2 - col1)); ((IBuffer)monoDocument).Insert(monoDocument.Length, data.Document.GetTextAt(curLine.Offset + col1, col2 - col1)); } if (lineNr < selection.MaxLine) { // Clipboard line end needs to be system dependend and not the document one. ((IBuffer)copiedDocument).Insert(copiedDocument.Length, Environment.NewLine); // \r in mono document stands for block selection line end. ((IBuffer)monoDocument).Insert(monoDocument.Length, "\r"); } } line = data.Document.GetLine(selection.MinLine); spanStack = line.StartSpan.Clone(); SyntaxModeService.ScanSpans(data.Document, this.mode, this.mode, spanStack, line.Offset, line.Offset + startCol); this.copiedDocument.GetLine(DocumentLocation.MinLine).StartSpan = spanStack; break; } } else { copiedDocument = null; } }
internal void DeleteSelection(Selection selection) { if (selection == null) { throw new ArgumentNullException("selection"); } switch (selection.SelectionMode) { case SelectionMode.Normal: ISegment segment = selection.GetSelectionRange(this); if (Caret.Offset > segment.Offset) { Caret.Offset -= System.Math.Min(segment.Length, Caret.Offset - segment.Offset); } int len = System.Math.Min(segment.Length, Document.Length - segment.Offset); if (len > 0) { Remove(segment.Offset, len); } break; case SelectionMode.Block: DocumentLocation visStart = LogicalToVisualLocation(selection.Anchor); DocumentLocation visEnd = LogicalToVisualLocation(selection.Lead); int startCol = System.Math.Min(visStart.Column, visEnd.Column); int endCol = System.Math.Max(visStart.Column, visEnd.Column); bool preserve = Caret.PreserveSelection; Caret.PreserveSelection = true; for (int lineNr = selection.MinLine; lineNr <= selection.MaxLine; lineNr++) { LineSegment curLine = Document.GetLine(lineNr); int col1 = curLine.GetLogicalColumn(this, startCol) - 1; int col2 = System.Math.Min(curLine.GetLogicalColumn(this, endCol) - 1, curLine.EditableLength); if (col1 >= col2) { continue; } Remove(curLine.Offset + col1, col2 - col1); if (Caret.Line == lineNr && Caret.Column >= col1) { Caret.Column = col1 + 1; } } int column = System.Math.Min(selection.Anchor.Column, selection.Lead.Column); selection.Anchor = new DocumentLocation(selection.Anchor.Line, column); selection.Lead = new DocumentLocation(selection.Lead.Line, column); Caret.Column = column; Caret.PreserveSelection = preserve; break; } }
void SetColumn() { LineSegment curLine = this.document.GetLine(this.Line); if (curLine == null) { return; } this.location.Column = curLine.GetLogicalColumn(editor, this.DesiredColumn); if (curLine.GetVisualColumn(editor, this.location.Column) < this.DesiredColumn) { this.location.Column = editor.GetNextVirtualColumn(Line, this.location.Column); } else { if (this.Column > curLine.EditableLength) { this.location.Column = System.Math.Min(curLine.EditableLength, System.Math.Max(0, this.Column)); if (AllowCaretBehindLineEnd) { this.location.Column = editor.GetNextVirtualColumn(Line, this.location.Column); } } } }
void SetColumn() { LineSegment curLine = TextEditorData.Document.GetLine(this.Line); if (curLine == null) { return; } this.location.Column = curLine.GetLogicalColumn(TextEditorData, this.DesiredColumn); if (curLine.GetVisualColumn(TextEditorData, this.location.Column) < this.DesiredColumn) { this.location.Column = TextEditorData.GetNextVirtualColumn(Line, this.location.Column); } else { if (this.Column > curLine.EditableLength + 1) { this.location.Column = System.Math.Min(curLine.EditableLength + 1, System.Math.Max(DocumentLocation.MinColumn, this.Column)); if (AllowCaretBehindLineEnd) { this.location.Column = TextEditorData.GetNextVirtualColumn(Line, this.location.Column); } } } }
public LayoutWrapper CreateLinePartLayout (ISyntaxMode mode, LineSegment line, int logicalRulerColumn, int offset, int length, int selectionStart, int selectionEnd) { bool containsPreedit = textEditor.ContainsPreedit (offset, length); LayoutDescriptor descriptor; if (!containsPreedit && layoutDict.TryGetValue (line, out descriptor)) { bool isInvalid; if (descriptor.Equals (line, offset, length, selectionStart, selectionEnd, out isInvalid) && descriptor.Layout != null) { return descriptor.Layout; } descriptor.Dispose (); layoutDict.Remove (line); } var wrapper = new LayoutWrapper (PangoUtil.CreateLayout (textEditor)); wrapper.IsUncached = containsPreedit; if (logicalRulerColumn < 0) logicalRulerColumn = line.GetLogicalColumn (textEditor.GetTextEditorData (), textEditor.Options.RulerColumn); var atts = new FastPangoAttrList (); wrapper.Layout.Alignment = Pango.Alignment.Left; wrapper.Layout.FontDescription = textEditor.Options.Font; wrapper.Layout.Tabs = tabArray; StringBuilder textBuilder = new StringBuilder (); var chunks = GetCachedChunks (mode, Document, textEditor.ColorStyle, line, offset, length); foreach (var chunk in chunks) { try { textBuilder.Append (Document.GetTextAt (chunk)); } catch { Console.WriteLine (chunk); } } var spanStack = line.StartSpan; int lineOffset = line.Offset; string lineText = textBuilder.ToString (); uint preeditLength = 0; if (containsPreedit) { lineText = lineText.Insert (textEditor.preeditOffset - offset, textEditor.preeditString); preeditLength = (uint)textEditor.preeditString.Length; } char[] lineChars = lineText.ToCharArray (); //int startOffset = offset, endOffset = offset + length; uint curIndex = 0, byteIndex = 0; uint curChunkIndex = 0, byteChunkIndex = 0; uint oldEndIndex = 0; foreach (Chunk chunk in chunks) { ChunkStyle chunkStyle = chunk != null ? textEditor.ColorStyle.GetChunkStyle (chunk) : null; spanStack = chunk.SpanStack ?? spanStack; foreach (TextMarker marker in line.Markers) chunkStyle = marker.GetStyle (chunkStyle); if (chunkStyle != null) { //startOffset = chunk.Offset; //endOffset = chunk.EndOffset; uint startIndex = (uint)(oldEndIndex); uint endIndex = (uint)(startIndex + chunk.Length); oldEndIndex = endIndex; HandleSelection (lineOffset, logicalRulerColumn, selectionStart, selectionEnd, chunk.Offset, chunk.EndOffset, delegate(int start, int end) { if (containsPreedit) { if (textEditor.preeditOffset < start) start += (int)preeditLength; if (textEditor.preeditOffset < end) end += (int)preeditLength; } var si = TranslateToUTF8Index (lineChars, (uint)(startIndex + start - chunk.Offset), ref curIndex, ref byteIndex); var ei = TranslateToUTF8Index (lineChars, (uint)(startIndex + end - chunk.Offset), ref curIndex, ref byteIndex); atts.AddForegroundAttribute (chunkStyle.Color, si, ei); if (!chunkStyle.TransparentBackround && GetPixel (ColorStyle.Default.BackgroundColor) != GetPixel (chunkStyle.BackgroundColor)) { wrapper.AddBackground (chunkStyle.CairoBackgroundColor, (int)si, (int)ei); } else if (chunk.SpanStack != null && ColorStyle != null) { foreach (var span in chunk.SpanStack) { if (span == null) continue; var spanStyle = ColorStyle.GetChunkStyle (span.Color); if (!spanStyle.TransparentBackround && GetPixel (ColorStyle.Default.BackgroundColor) != GetPixel (spanStyle.BackgroundColor)) { wrapper.AddBackground (spanStyle.CairoBackgroundColor, (int)si, (int)ei); break; } } } }, delegate(int start, int end) { if (containsPreedit) { if (textEditor.preeditOffset < start) start += (int)preeditLength; if (textEditor.preeditOffset < end) end += (int)preeditLength; } var si = TranslateToUTF8Index (lineChars, (uint)(startIndex + start - chunk.Offset), ref curIndex, ref byteIndex); var ei = TranslateToUTF8Index (lineChars, (uint)(startIndex + end - chunk.Offset), ref curIndex, ref byteIndex); atts.AddForegroundAttribute (SelectionColor.Color, si, ei); if (!wrapper.StartSet) wrapper.SelectionStartIndex = (int)si; wrapper.SelectionEndIndex = (int)ei; }); var translatedStartIndex = TranslateToUTF8Index (lineChars, (uint)startIndex, ref curChunkIndex, ref byteChunkIndex); var translatedEndIndex = TranslateToUTF8Index (lineChars, (uint)endIndex, ref curChunkIndex, ref byteChunkIndex); if (chunkStyle.Bold) atts.AddWeightAttribute (Pango.Weight.Bold, translatedStartIndex, translatedEndIndex); if (chunkStyle.Italic) atts.AddStyleAttribute (Pango.Style.Italic, translatedStartIndex, translatedEndIndex); if (chunkStyle.Underline) atts.AddUnderlineAttribute (Pango.Underline.Single, translatedStartIndex, translatedEndIndex); } } if (containsPreedit) { var si = TranslateToUTF8Index (lineChars, (uint)(textEditor.preeditOffset - offset), ref curIndex, ref byteIndex); var ei = TranslateToUTF8Index (lineChars, (uint)(textEditor.preeditOffset - offset + preeditLength), ref curIndex, ref byteIndex); atts.Splice (textEditor.preeditAttrs, (int)si, (int)(ei - si)); } wrapper.LineChars = lineChars; wrapper.Layout.SetText (lineText); wrapper.EolSpanStack = spanStack; atts.AssignTo (wrapper.Layout); atts.Dispose (); int w, h; wrapper.Layout.GetSize (out w, out h); wrapper.PangoWidth = w; selectionStart = System.Math.Max (line.Offset - 1, selectionStart); selectionEnd = System.Math.Min (line.EndOffsetIncludingDelimiter + 1, selectionEnd); descriptor = new LayoutDescriptor (line, offset, length, wrapper, selectionStart, selectionEnd); if (!containsPreedit) layoutDict[line] = descriptor; return wrapper; }
void GetSelectionOffsets (LineSegment line, out int selectionStart, out int selectionEnd) { selectionStart = -1; selectionEnd = -1; if (textEditor.IsSomethingSelected) { TextSegment segment = textEditor.SelectionRange; selectionStart = segment.Offset; selectionEnd = segment.EndOffset; if (textEditor.SelectionMode == SelectionMode.Block) { DocumentLocation start = textEditor.MainSelection.Anchor; DocumentLocation end = textEditor.MainSelection.Lead; DocumentLocation visStart = textEditor.LogicalToVisualLocation (start); DocumentLocation visEnd = textEditor.LogicalToVisualLocation (end); int lineOffset = line.Offset; int lineNumber = Document.OffsetToLineNumber (lineOffset); if (textEditor.MainSelection.MinLine <= lineNumber && lineNumber <= textEditor.MainSelection.MaxLine) { selectionStart = lineOffset + line.GetLogicalColumn (this.textEditor.GetTextEditorData (), System.Math.Min (visStart.Column, visEnd.Column)) - 1; selectionEnd = lineOffset + line.GetLogicalColumn (this.textEditor.GetTextEditorData (), System.Math.Max (visStart.Column, visEnd.Column)) - 1; } } } }
public double ColumnToX (LineSegment line, int column) { column--; if (line == null || line.Length == 0 || column < 0) return 0; int logicalRulerColumn = line.GetLogicalColumn (textEditor.GetTextEditorData (), textEditor.Options.RulerColumn); int lineOffset = line.Offset; StringBuilder textBuilder = new StringBuilder (); ISyntaxMode mode = Document.SyntaxMode != null && textEditor.Options.EnableSyntaxHighlighting ? Document.SyntaxMode : new SyntaxMode (Document); var startChunk = GetCachedChunks (mode, Document, textEditor.ColorStyle, line, lineOffset, line.Length); foreach (Chunk chunk in startChunk) { try { textBuilder.Append (Document.GetTextAt (chunk)); } catch (Exception e) { Console.WriteLine (e); return 0; } } string lineText = textBuilder.ToString (); char[] lineChars = lineText.ToCharArray (); bool containsPreedit = textEditor.ContainsPreedit (lineOffset, line.Length); uint preeditLength = 0; if (containsPreedit) { lineText = lineText.Insert (textEditor.preeditOffset - lineOffset, textEditor.preeditString); preeditLength = (uint)textEditor.preeditString.Length; } if (column < lineText.Length) lineText = lineText.Substring (0, column); var layout = PangoUtil.CreateLayout (textEditor, lineText); layout.Alignment = Pango.Alignment.Left; layout.FontDescription = textEditor.Options.Font; layout.Tabs = tabArray; int startOffset = lineOffset, endOffset = lineOffset + line.Length; uint curIndex = 0, byteIndex = 0; uint curChunkIndex = 0, byteChunkIndex = 0; List<Pango.Attribute> attributes = new List<Pango.Attribute> (); uint oldEndIndex = 0; foreach (Chunk chunk in startChunk) { ChunkStyle chunkStyle = chunk != null ? textEditor.ColorStyle.GetChunkStyle (chunk) : null; foreach (TextMarker marker in line.Markers) chunkStyle = marker.GetStyle (chunkStyle); if (chunkStyle != null) { startOffset = chunk.Offset; endOffset = chunk.EndOffset; uint startIndex = (uint)(oldEndIndex); uint endIndex = (uint)(startIndex + chunk.Length); oldEndIndex = endIndex; if (containsPreedit) { if (textEditor.preeditOffset < startOffset) startIndex += preeditLength; if (textEditor.preeditOffset < endOffset) endIndex += preeditLength; } HandleSelection (lineOffset, logicalRulerColumn, - 1, -1, chunk.Offset, chunk.EndOffset, delegate(int start, int end) { Pango.AttrForeground foreGround = new Pango.AttrForeground (chunkStyle.Color.Red, chunkStyle.Color.Green, chunkStyle.Color.Blue); foreGround.StartIndex = TranslateToUTF8Index (lineChars, (uint)(startIndex + start - chunk.Offset), ref curIndex, ref byteIndex); foreGround.EndIndex = TranslateToUTF8Index (lineChars, (uint)(startIndex + end - chunk.Offset), ref curIndex, ref byteIndex); attributes.Add (foreGround); if (!chunkStyle.TransparentBackround) { var background = new Pango.AttrBackground (chunkStyle.BackgroundColor.Red, chunkStyle.BackgroundColor.Green, chunkStyle.BackgroundColor.Blue); background.StartIndex = foreGround.StartIndex; background.EndIndex = foreGround.EndIndex; attributes.Add (background); } }, delegate(int start, int end) { Pango.AttrForeground selectedForeground = new Pango.AttrForeground (SelectionColor.Color.Red, SelectionColor.Color.Green, SelectionColor.Color.Blue); selectedForeground.StartIndex = TranslateToUTF8Index (lineChars, (uint)(startIndex + start - chunk.Offset), ref curIndex, ref byteIndex); selectedForeground.EndIndex = TranslateToUTF8Index (lineChars, (uint)(startIndex + end - chunk.Offset), ref curIndex, ref byteIndex); attributes.Add (selectedForeground); }); var translatedStartIndex = TranslateToUTF8Index (lineChars, (uint)startIndex, ref curChunkIndex, ref byteChunkIndex); var translatedEndIndex = TranslateToUTF8Index (lineChars, (uint)endIndex, ref curChunkIndex, ref byteChunkIndex); if (chunkStyle.Bold) { Pango.AttrWeight attrWeight = new Pango.AttrWeight (Pango.Weight.Bold); attrWeight.StartIndex = translatedStartIndex; attrWeight.EndIndex = translatedEndIndex; attributes.Add (attrWeight); } if (chunkStyle.Italic) { Pango.AttrStyle attrStyle = new Pango.AttrStyle (Pango.Style.Italic); attrStyle.StartIndex = translatedStartIndex; attrStyle.EndIndex = translatedEndIndex; attributes.Add (attrStyle); } if (chunkStyle.Underline) { Pango.AttrUnderline attrUnderline = new Pango.AttrUnderline (Pango.Underline.Single); attrUnderline.StartIndex = translatedStartIndex; attrUnderline.EndIndex = translatedEndIndex; attributes.Add (attrUnderline); } } } Pango.AttrList attributeList = new Pango.AttrList (); attributes.ForEach (attr => attributeList.Insert (attr)); layout.Attributes = attributeList; Pango.Rectangle ink_rect, logical_rect; layout.GetExtents (out ink_rect, out logical_rect); attributes.ForEach (attr => attr.Dispose ()); attributeList.Dispose (); layout.Dispose (); return (logical_rect.Width + Pango.Scale.PangoScale - 1) / Pango.Scale.PangoScale; }
public DocumentLocation PointToLocation (double xp, double yp) { lineNumber = System.Math.Min (margin.YToLine (yp + margin.textEditor.VAdjustment.Value), margin.Document.LineCount); line = lineNumber <= margin.Document.LineCount ? margin.Document.GetLine (lineNumber) : null; if (line == null) return DocumentLocation.Empty; int offset = line.Offset; yp = ((int)yp % margin.LineHeight); xp -= margin.TextStartPosition; xp += margin.textEditor.HAdjustment.Value; xp *= Pango.Scale.PangoScale; yp *= Pango.Scale.PangoScale; yp = System.Math.Max (0, yp); if (xp < 0) return new DocumentLocation (lineNumber, DocumentLocation.MinColumn); int column = DocumentLocation.MinColumn; ISyntaxMode mode = margin.Document.SyntaxMode != null && margin.textEditor.Options.EnableSyntaxHighlighting ? margin.Document.SyntaxMode : new SyntaxMode (margin.Document); IEnumerable<FoldSegment> foldings = margin.Document.GetStartFoldings (line); bool done = false; Pango.Layout measueLayout = null; restart: int logicalRulerColumn = line.GetLogicalColumn(margin.textEditor.GetTextEditorData(), margin.textEditor.Options.RulerColumn); foreach (FoldSegment folding in foldings.Where(f => f.IsFolded)) { int foldOffset = folding.StartLine.Offset + folding.Column - 1; if (foldOffset < offset) continue; layoutWrapper = margin.CreateLinePartLayout(mode, line, logicalRulerColumn, line.Offset, foldOffset - offset, -1, -1); done |= ConsumeLayout ((int)(xp - xPos), (int)yp); if (done) break; int height, width; layoutWrapper.Layout.GetPixelSize (out width, out height); xPos += width * (int)Pango.Scale.PangoScale; if (measueLayout == null) { measueLayout = PangoUtil.CreateLayout (margin.textEditor, folding.Description); measueLayout.FontDescription = margin.textEditor.Options.Font; } int delta; measueLayout.GetPixelSize (out delta, out height); delta *= (int)Pango.Scale.PangoScale; xPos += delta; if (xPos - delta / 2 >= xp) { index = foldOffset - offset; done = true; break; } offset = folding.EndLine.Offset + folding.EndColumn; DocumentLocation foldingEndLocation = margin.Document.OffsetToLocation(offset); lineNumber = foldingEndLocation.Line; column = foldingEndLocation.Column; if (xPos >= xp) { index = 0; done = true; break; } if (folding.EndLine != line) { line = folding.EndLine; foldings = margin.Document.GetStartFoldings (line); goto restart; } } if (!done) { layoutWrapper = margin.CreateLinePartLayout(mode, line, logicalRulerColumn, offset, line.Offset + line.Length - offset, -1, -1); ConsumeLayout ((int)(xp - xPos), (int)yp); } if (measueLayout != null) measueLayout.Dispose (); return new DocumentLocation (lineNumber, column + index); }
protected internal override void Draw (Cairo.Context cr, Cairo.Rectangle area, LineSegment line, int lineNr, double x, double y, double _lineHeight) { // double xStart = System.Math.Max (area.X, XOffset); // xStart = System.Math.Max (0, xStart); var lineArea = new Cairo.Rectangle (XOffset - 1, y, textEditor.Allocation.Width - XOffset + 1, _lineHeight); int width, height; double pangoPosition = (x - textEditor.HAdjustment.Value + TextStartPosition) * Pango.Scale.PangoScale; defaultBgColor = Document.ReadOnly ? ColorStyle.ReadOnlyTextBg : ColorStyle.Default.CairoBackgroundColor; // Draw the default back color for the whole line. Colors other than the default // background will be drawn when rendering the text chunks. DrawRectangleWithRuler (cr, x, lineArea, defaultBgColor, true); bool isSelectionDrawn = false; if (BackgroundRenderer != null) BackgroundRenderer.Draw (cr, area, line, x, y, _lineHeight); // Check if line is beyond the document length if (line == null) { if (textEditor.Options.ShowInvalidLines) DrawInvalidLineMarker (cr, pangoPosition / Pango.Scale.PangoScale, y); var marker = Document.GetExtendingTextMarker (lineNr); if (marker != null) marker.Draw (textEditor, cr, lineNr, lineArea); return; } IEnumerable<FoldSegment> foldings = Document.GetStartFoldings (line); int offset = line.Offset; int caretOffset = Caret.Offset; bool isEolFolded = false; restart: int logicalRulerColumn = line.GetLogicalColumn (textEditor.GetTextEditorData (), textEditor.Options.RulerColumn); foreach (FoldSegment folding in foldings) { int foldOffset = folding.StartLine.Offset + folding.Column - 1; if (foldOffset < offset) continue; if (folding.IsFolded) { DrawLinePart (cr, line, lineNr, logicalRulerColumn, offset, foldOffset - offset, ref pangoPosition, ref isSelectionDrawn, y, area.X + area.Width); offset = folding.EndLine.Offset + folding.EndColumn; markerLayout.SetText (folding.Description); markerLayout.GetSize (out width, out height); bool isFoldingSelected = !this.HideSelection && textEditor.IsSomethingSelected && textEditor.SelectionRange.Contains (folding.Segment); double pixelX = pangoPosition / Pango.Scale.PangoScale; double pixelWidth = (pangoPosition + width) / Pango.Scale.PangoScale - pixelX; var foldingRectangle = new Cairo.Rectangle (pixelX + 0.5, y + 0.5, pixelWidth - cr.LineWidth, this.LineHeight - cr.LineWidth); if (BackgroundRenderer == null) { cr.Color = isFoldingSelected ? SelectionColor.CairoBackgroundColor : defaultBgColor; cr.Rectangle (foldingRectangle); cr.Fill (); } cr.Color = isFoldingSelected ? SelectionColor.CairoColor : ColorStyle.FoldLine.CairoColor; cr.Rectangle (foldingRectangle); cr.Stroke (); cr.Save (); cr.Translate (pangoPosition / Pango.Scale.PangoScale, y); cr.Color = isFoldingSelected ? SelectionColor.CairoColor : ColorStyle.FoldLine.CairoColor; cr.ShowLayout (markerLayout); cr.Restore (); if (caretOffset == foldOffset && !string.IsNullOrEmpty (folding.Description)) SetVisibleCaretPosition ((int)(pangoPosition / Pango.Scale.PangoScale), y); pangoPosition += width; if (caretOffset == foldOffset + folding.Length && !string.IsNullOrEmpty (folding.Description)) SetVisibleCaretPosition ((int)(pangoPosition / Pango.Scale.PangoScale), y); if (folding.EndLine != line) { line = folding.EndLine; lineNr = Document.OffsetToLineNumber (line.Offset); foldings = Document.GetStartFoldings (line); isEolFolded = line.Length <= folding.EndColumn; goto restart; } isEolFolded = line.Length <= folding.EndColumn; } } // Draw remaining line - must be called for empty line parts as well because the caret may be at this positon // and the caret position is calculated in DrawLinePart. if (line.EndOffsetIncludingDelimiter - offset >= 0) DrawLinePart (cr, line, lineNr, logicalRulerColumn, offset, line.Offset + line.Length - offset, ref pangoPosition, ref isSelectionDrawn, y, area.X + area.Width); bool isEolSelected = !this.HideSelection && textEditor.IsSomethingSelected && textEditor.SelectionMode == SelectionMode.Normal && textEditor.SelectionRange.Contains (line.Offset + line.Length); lineArea = new Cairo.Rectangle (pangoPosition / Pango.Scale.PangoScale, lineArea.Y, textEditor.Allocation.Width - pangoPosition / Pango.Scale.PangoScale, lineArea.Height); if (textEditor.SelectionMode == SelectionMode.Block && textEditor.IsSomethingSelected && textEditor.SelectionRange.Contains (line.Offset + line.Length)) { DocumentLocation start = textEditor.MainSelection.Anchor; DocumentLocation end = textEditor.MainSelection.Lead; DocumentLocation visStart = textEditor.LogicalToVisualLocation (start); DocumentLocation visEnd = textEditor.LogicalToVisualLocation (end); double x1 = this.ColumnToX (line, visStart.Column); double x2 = this.ColumnToX (line, visEnd.Column); if (x1 > x2) { var tmp = x1; x1 = x2; x2 = tmp; } x1 += XOffset - textEditor.HAdjustment.Value; x2 += XOffset - textEditor.HAdjustment.Value; if (x2 > lineArea.X) { if (x1 - lineArea.X > 0) { DrawRectangleWithRuler (cr, x, new Cairo.Rectangle (lineArea.X, lineArea.Y, x1 - lineArea.X, lineArea.Height), defaultBgColor, false); lineArea = new Cairo.Rectangle (x1, lineArea.Y, lineArea.Width, lineArea.Height); } DrawRectangleWithRuler (cr, x, new Cairo.Rectangle (lineArea.X, lineArea.Y, x2 - lineArea.X, lineArea.Height), this.SelectionColor.CairoBackgroundColor, false); lineArea = new Cairo.Rectangle (x2, lineArea.Y, textEditor.Allocation.Width - lineArea.X, lineArea.Height); } } if (!isSelectionDrawn) { if (isEolSelected) { if (!Platform.IsMac) { // prevent "gaps" in the selection drawing ('fuzzy' lines problem) lineArea = new Cairo.Rectangle (pangoPosition / Pango.Scale.PangoScale, lineArea.Y, textEditor.Allocation.Width - pangoPosition / Pango.Scale.PangoScale + 1, lineArea.Height); } else { // prevent "gaps" in the selection drawing ('fuzzy' lines problem) lineArea = new Cairo.Rectangle (pangoPosition / Pango.Scale.PangoScale - 1, lineArea.Y, textEditor.Allocation.Width - pangoPosition / Pango.Scale.PangoScale + 1, lineArea.Height); } DrawRectangleWithRuler (cr, x, lineArea, this.SelectionColor.CairoBackgroundColor, false); } else if (!(HighlightCaretLine || textEditor.Options.HighlightCaretLine) || Caret.Line != lineNr) { LayoutWrapper wrapper = GetLayout (line); if (wrapper.EolSpanStack != null) { foreach (var span in wrapper.EolSpanStack) { var spanStyle = textEditor.ColorStyle.GetChunkStyle (span.Color); if (!spanStyle.TransparentBackround && GetPixel (ColorStyle.Default.BackgroundColor) != GetPixel (spanStyle.BackgroundColor)) { DrawRectangleWithRuler (cr, x, lineArea, spanStyle.CairoBackgroundColor, false); break; } } } } else { double xPos = pangoPosition / Pango.Scale.PangoScale; DrawCaretLineMarker (cr, xPos, y, lineArea.X + lineArea.Width - xPos); } } if (!isEolFolded && textEditor.Options.ShowEolMarkers) DrawEolMarker (cr, line, isEolSelected, pangoPosition / Pango.Scale.PangoScale, y); var extendingMarker = Document.GetExtendingTextMarker (lineNr); if (extendingMarker != null) extendingMarker.Draw (textEditor, cr, lineNr, lineArea); lastLineRenderWidth = pangoPosition / Pango.Scale.PangoScale; }
void HandleSelection (LineSegment line, int selectionStart, int selectionEnd, int startOffset, int endOffset, HandleSelectionDelegate handleNotSelected, HandleSelectionDelegate handleSelected) { int selectionStartColumn = selectionStart - line.Offset; int selectionEndColumn = selectionEnd - line.Offset; int logicalRulerColumn = line.GetLogicalColumn (textEditor.GetTextEditorData (), textEditor.Options.RulerColumn); int rulerOffset = line.Offset + logicalRulerColumn; if (textEditor.Options.ShowRuler && selectionStartColumn < logicalRulerColumn && logicalRulerColumn < selectionEndColumn && startOffset < rulerOffset && rulerOffset < endOffset) { InternalHandleSelection (selectionStart, selectionEnd, startOffset, rulerOffset, handleNotSelected, handleSelected); InternalHandleSelection (selectionStart, selectionEnd, rulerOffset, endOffset, handleNotSelected, handleSelected); } else { InternalHandleSelection (selectionStart, selectionEnd, startOffset, endOffset, handleNotSelected, handleSelected); } }
public LayoutWrapper CreateLinePartLayout (SyntaxMode mode, LineSegment line, int logicalRulerColumn, int offset, int length, int selectionStart, int selectionEnd) { return GetCachedLayout (line, offset, length, selectionStart, selectionEnd, delegate(LayoutWrapper wrapper) { if (logicalRulerColumn < 0) logicalRulerColumn = line.GetLogicalColumn(textEditor.GetTextEditorData(), textEditor.Options.RulerColumn); var atts = new FastPangoAttrList (); wrapper.Layout.Alignment = Pango.Alignment.Left; wrapper.Layout.FontDescription = textEditor.Options.Font; wrapper.Layout.Tabs = tabArray; StringBuilder textBuilder = new StringBuilder (); Chunk startChunk = GetCachedChunks (mode, Document, textEditor.ColorStyle, line, offset, length); for (Chunk chunk = startChunk; chunk != null; chunk = chunk != null ? chunk.Next : null) { try { textBuilder.Append (chunk.GetText (Document)); } catch { Console.WriteLine (chunk); } } var spanStack = line.StartSpan; int lineOffset = line.Offset; string lineText = textBuilder.ToString (); bool containsPreedit = !string.IsNullOrEmpty (textEditor.preeditString) && offset <= textEditor.preeditOffset && textEditor.preeditOffset <= offset + length; uint preeditLength = 0; if (containsPreedit) { lineText = lineText.Insert (textEditor.preeditOffset - offset, textEditor.preeditString); preeditLength = (uint)textEditor.preeditString.Length; } char[] lineChars = lineText.ToCharArray (); //int startOffset = offset, endOffset = offset + length; uint curIndex = 0, byteIndex = 0; uint curChunkIndex = 0, byteChunkIndex = 0; uint oldEndIndex = 0; for (Chunk chunk = startChunk; chunk != null; chunk = chunk != null ? chunk.Next : null) { ChunkStyle chunkStyle = chunk != null ? chunk.GetChunkStyle (textEditor.ColorStyle) : null; spanStack = chunk.SpanStack ?? spanStack; foreach (TextMarker marker in line.Markers) chunkStyle = marker.GetStyle (chunkStyle); if (chunkStyle != null) { //startOffset = chunk.Offset; //endOffset = chunk.EndOffset; uint startIndex = (uint)(oldEndIndex); uint endIndex = (uint)(startIndex + chunk.Length); oldEndIndex = endIndex; HandleSelection(lineOffset, logicalRulerColumn, selectionStart, selectionEnd, chunk.Offset, chunk.EndOffset, delegate(int start, int end) { if (containsPreedit) { if (textEditor.preeditOffset < start) start += (int)preeditLength; if (textEditor.preeditOffset < end) end += (int)preeditLength; } var si = TranslateToUTF8Index (lineChars, (uint)(startIndex + start - chunk.Offset), ref curIndex, ref byteIndex); var ei = TranslateToUTF8Index (lineChars, (uint)(startIndex + end - chunk.Offset), ref curIndex, ref byteIndex); atts.AddForegroundAttribute (chunkStyle.Color, si, ei); if (!chunkStyle.TransparentBackround && GetPixel (ColorStyle.Default.BackgroundColor) != GetPixel (chunkStyle.BackgroundColor)) { wrapper.AddBackground (chunkStyle.CairoBackgroundColor, (int)si, (int)ei); } else if (chunk.SpanStack != null && ColorStyle != null) { foreach (var span in chunk.SpanStack) { if (span == null) continue; var spanStyle = ColorStyle.GetChunkStyle (span.Color); if (!spanStyle.TransparentBackround && GetPixel (ColorStyle.Default.BackgroundColor) != GetPixel (spanStyle.BackgroundColor)) { wrapper.AddBackground (spanStyle.CairoBackgroundColor, (int)si, (int)ei); break; } } } }, delegate(int start, int end) { if (containsPreedit) { if (textEditor.preeditOffset < start) start += (int)preeditLength; if (textEditor.preeditOffset < end) end += (int)preeditLength; } var si = TranslateToUTF8Index (lineChars, (uint)(startIndex + start - chunk.Offset), ref curIndex, ref byteIndex); var ei = TranslateToUTF8Index (lineChars, (uint)(startIndex + end - chunk.Offset), ref curIndex, ref byteIndex); atts.AddForegroundAttribute (SelectionColor.Color, si, ei); if (!wrapper.StartSet) wrapper.SelectionStartIndex = (int)si; wrapper.SelectionEndIndex = (int)ei; }); var translatedStartIndex = TranslateToUTF8Index (lineChars, (uint)startIndex, ref curChunkIndex, ref byteChunkIndex); var translatedEndIndex = TranslateToUTF8Index (lineChars, (uint)endIndex, ref curChunkIndex, ref byteChunkIndex); if (chunkStyle.Bold) atts.AddWeightAttribute (Pango.Weight.Bold, translatedStartIndex, translatedEndIndex); if (chunkStyle.Italic) atts.AddStyleAttribute (Pango.Style.Italic, translatedStartIndex, translatedEndIndex); if (chunkStyle.Underline) atts.AddUnderlineAttribute (Pango.Underline.Single, translatedStartIndex, translatedEndIndex); } } if (containsPreedit) { var si = TranslateToUTF8Index (lineChars, (uint)(textEditor.preeditOffset - offset), ref curIndex, ref byteIndex); var ei = TranslateToUTF8Index (lineChars, (uint)(textEditor.preeditOffset - offset + preeditLength), ref curIndex, ref byteIndex); atts.AddUnderlineAttribute (Pango.Underline.Single, si, ei); var parser = Document.SyntaxMode.CreateSpanParser (Document, Document.SyntaxMode, line, line.StartSpan); parser.ParseSpans (line.Offset, textEditor.preeditOffset); var preEditColor = parser.CurSpan != null ? ColorStyle.GetChunkStyle (parser.CurSpan.Color).Color : ColorStyle.Default.Color; atts.AddForegroundAttribute (preEditColor, si, ei); } wrapper.LineChars = lineChars; wrapper.Layout.SetText (lineText); wrapper.EolSpanStack = spanStack; atts.AssignTo (wrapper.Layout); atts.Dispose (); int w, h; wrapper.Layout.GetSize (out w, out h); wrapper.PangoWidth = w; }); }
protected void InsertCharacter(uint unicodeKey) { if (!textEditorData.CanEdit(Data.Caret.Line)) { return; } HideMouseCursor(); using (var undo = Document.OpenUndoGroup()) { textEditorData.DeleteSelectedText(textEditorData.IsSomethingSelected ? textEditorData.MainSelection.SelectionMode != SelectionMode.Block : true); char ch = (char)unicodeKey; if (!char.IsControl(ch) && textEditorData.CanEdit(Caret.Line)) { LineSegment line = Document.GetLine(Caret.Line); if (Caret.IsInInsertMode || Caret.Column >= line.EditableLength + 1) { string text = Caret.Column > line.EditableLength + 1 ? textEditorData.GetVirtualSpaces(Caret.Line, Caret.Column) + ch.ToString() : ch.ToString(); if (textEditorData.IsSomethingSelected && textEditorData.MainSelection.SelectionMode == SelectionMode.Block) { int length = 0; var visualInsertLocation = editor.LogicalToVisualLocation(Caret.Location); for (int lineNumber = textEditorData.MainSelection.MinLine; lineNumber <= textEditorData.MainSelection.MaxLine; lineNumber++) { LineSegment lineSegment = textEditorData.GetLine(lineNumber); int insertOffset = lineSegment.GetLogicalColumn(textEditorData, visualInsertLocation.Column) - 1; string textToInsert; if (lineSegment.EditableLength < insertOffset) { int visualLastColumn = lineSegment.GetVisualColumn(textEditorData, lineSegment.EditableLength + 1); int charsToInsert = visualInsertLocation.Column - visualLastColumn; int spaceCount = charsToInsert % editor.Options.TabSize; textToInsert = new string ('\t', (charsToInsert - spaceCount) / editor.Options.TabSize) + new string (' ', spaceCount) + text; insertOffset = lineSegment.EditableLength; } else { textToInsert = text; } length = textEditorData.Insert(lineSegment.Offset + insertOffset, textToInsert); } Caret.PreserveSelection = true; Caret.Column += length - 1; textEditorData.MainSelection.Lead = new DocumentLocation(textEditorData.MainSelection.Lead.Line, Caret.Column + 1); textEditorData.MainSelection.Anchor = new DocumentLocation(textEditorData.MainSelection.Anchor.Line, Caret.Column + 1); Document.CommitMultipleLineUpdate(textEditorData.MainSelection.MinLine, textEditorData.MainSelection.MaxLine); } else { int length = textEditorData.Insert(Caret.Offset, text); Caret.Column += length - 1; } } else { int length = textEditorData.Replace(Caret.Offset, 1, ch.ToString()); if (length > 1) { Caret.Offset += length - 1; } } // That causes unnecessary redraws: // bool autoScroll = Caret.AutoScrollToCaret; Caret.Column++; if (Caret.PreserveSelection) { Caret.PreserveSelection = false; } // Caret.AutoScrollToCaret = autoScroll; // if (autoScroll) // Editor.ScrollToCaret (); // Document.RequestUpdate (new LineUpdate (Caret.Line)); // Document.CommitDocumentUpdate (); } } Document.OptimizeTypedUndo(); }
static int PasteFrom(Clipboard clipboard, TextEditorData data, bool preserveSelection, int insertionOffset, bool preserveState) { int result = -1; if (!data.CanEdit(data.Document.OffsetToLineNumber(insertionOffset))) { return(result); } if (clipboard.WaitIsTargetAvailable(CopyOperation.MD_ATOM)) { clipboard.RequestContents(CopyOperation.MD_ATOM, delegate(Clipboard clp, SelectionData selectionData) { if (selectionData.Length > 0) { byte[] selBytes = selectionData.Data; string text = System.Text.Encoding.UTF8.GetString(selBytes, 1, selBytes.Length - 1); bool pasteBlock = (selBytes [0] & 1) == 1; bool pasteLine = (selBytes [0] & 2) == 2; if (!pasteBlock && !pasteLine) { return; } data.Document.BeginAtomicUndo(); if (preserveSelection && data.IsSomethingSelected) { data.DeleteSelectedText(); } data.Caret.PreserveSelection = true; if (pasteBlock) { string[] lines = text.Split('\r'); int lineNr = data.Document.OffsetToLineNumber(insertionOffset); int col = insertionOffset - data.Document.GetLine(lineNr).Offset; int visCol = data.Document.GetLine(lineNr).GetVisualColumn(data, col); LineSegment curLine; int lineCol = col; result = 0; for (int i = 0; i < lines.Length; i++) { while (data.Document.LineCount <= lineNr + i) { data.Insert(data.Document.Length, Environment.NewLine); result += Environment.NewLine.Length; } curLine = data.Document.GetLine(lineNr + i); if (lines [i].Length > 0) { lineCol = curLine.GetLogicalColumn(data, visCol); if (curLine.EditableLength + 1 < lineCol) { result += lineCol - curLine.EditableLength; data.Insert(curLine.Offset + curLine.EditableLength, new string (' ', lineCol - curLine.EditableLength)); } data.Insert(curLine.Offset + lineCol, lines [i]); result += lines [i].Length; } if (!preserveState) { data.Caret.Offset = curLine.Offset + lineCol + lines [i].Length; } } } else if (pasteLine) { result = text.Length; LineSegment curLine = data.Document.GetLine(data.Caret.Line); data.Insert(curLine.Offset, text + data.EolMarker); if (!preserveState) { data.Caret.Offset += text.Length + data.EolMarker.Length; } } /* data.MainSelection = new Selection (data.Document.OffsetToLocation (insertionOffset), * data.Caret.Location, * lines.Length > 1 ? SelectionMode.Block : SelectionMode.Normal);*/ if (!preserveState) { data.ClearSelection(); } data.Caret.PreserveSelection = false; data.Document.EndAtomicUndo(); } }); } if (result < 0 && clipboard.WaitIsTextAvailable()) { clipboard.RequestText(delegate(Clipboard clp, string text) { if (string.IsNullOrEmpty(text)) { return; } data.Document.BeginAtomicUndo(); int caretPos = data.Caret.Offset; if (data.IsSomethingSelected && data.MainSelection.SelectionMode == SelectionMode.Block) { data.Caret.PreserveSelection = true; data.DeleteSelectedText(false); int textLength = 0; int minLine = data.MainSelection.MinLine; int maxLine = data.MainSelection.MaxLine; var visualInsertLocation = data.LogicalToVisualLocation(data.Caret.Location); for (int lineNumber = minLine; lineNumber <= maxLine; lineNumber++) { LineSegment lineSegment = data.GetLine(lineNumber); int insertOffset = lineSegment.GetLogicalColumn(data, visualInsertLocation.Column) - 1; if (lineSegment.EditableLength < insertOffset) { int visualLastColumn = lineSegment.GetVisualColumn(data, lineSegment.EditableLength + 1); int charsToInsert = visualInsertLocation.Column - visualLastColumn; int spaceCount = charsToInsert % data.Options.TabSize; string textToInsert = new string ('\t', (charsToInsert - spaceCount) / data.Options.TabSize) + new string (' ', spaceCount) + text; insertOffset = lineSegment.EditableLength; data.Insert(lineSegment.Offset + insertOffset, textToInsert); data.PasteText(lineSegment.Offset + insertOffset, textToInsert); } else { textLength = data.Insert(lineSegment.Offset + insertOffset, text); data.PasteText(lineSegment.Offset + insertOffset, text); } } data.Caret.Offset += textLength; data.MainSelection.Anchor = new DocumentLocation(System.Math.Max(DocumentLocation.MinLine, data.Caret.Line == minLine ? maxLine : minLine), System.Math.Max(DocumentLocation.MinColumn, data.Caret.Column - textLength)); data.MainSelection.Lead = new DocumentLocation(data.Caret.Line, data.Caret.Column); data.Caret.PreserveSelection = false; data.Document.CommitMultipleLineUpdate(data.MainSelection.MinLine, data.MainSelection.MaxLine); } else { ISegment selection = data.SelectionRange; if (preserveSelection && data.IsSomethingSelected) { data.DeleteSelectedText(); } data.Caret.PreserveSelection = true; //int oldLine = data.Caret.Line; int textLength = data.Insert(insertionOffset, text); result = textLength; if (data.IsSomethingSelected && data.SelectionRange.Offset >= insertionOffset) { data.SelectionRange.Offset += textLength; } if (data.IsSomethingSelected && data.MainSelection.GetAnchorOffset(data) >= insertionOffset) { data.MainSelection.Anchor = data.Document.OffsetToLocation(data.MainSelection.GetAnchorOffset(data) + textLength); } data.Caret.PreserveSelection = false; if (!preserveState) { data.Caret.Offset += textLength; } else { if (caretPos >= insertionOffset) { data.Caret.Offset += textLength; } if (selection != null) { int offset = selection.Offset; if (offset >= insertionOffset) { offset += textLength; } data.SelectionRange = new Segment(offset, selection.Length); } } data.PasteText(insertionOffset, text); } data.Document.EndAtomicUndo(); }); } return(result); }