<commit_before>﻿//
// Copyright (c) Antmicro
//
// This file is part of the Emul8 project.
// Full license details are defined in the 'LICENSE' file.
//
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using Terminal.Misc;
using Xwt;
using Xwt.Drawing;

namespace Terminal.Rows
{
    public class MonospaceTextRow : IRow
    {
        public MonospaceTextRow(string content)
        {
#if DEBUG
            if(content.Contains("\n"))
            {
                throw new ArgumentException("Content cannot contain a newline character.");
            }
#endif
            this.content = content;
            lengthInTextElements = new StringInfo(content).LengthInTextElements;
        }

        public double PrepareForDrawing(ILayoutParameters parameters)
        {
            defaultForeground = parameters.DefaultForeground;
            selectionColor = parameters.SelectionColor;
            textLayout = TextLayoutCache.GetValue(parameters);
            lineSize = LineSizeCache.GetValue(parameters);
            charWidth = CharSizeCache.GetValue(parameters).Width;
            MaxOffset = (int)(lineSize.Width / charWidth);
            return lineSize.Height * Math.Ceiling((lengthInTextElements == 0 ? 1 : lengthInTextElements) * charWidth / lineSize.Width);
        }

        public void Draw(Context ctx, Rectangle selectedArea, SelectionDirection selectionDirection, SelectionMode selectionMode)
        {
            ctx.SetColor(defaultForeground);
            var newLinesAt = new List<int> { 0 };
            var charsOnLine = (int)Math.Floor(lineSize.Width / charWidth);

            var result = new StringBuilder();
            var enumerator = StringInfo.GetTextElementEnumerator(content);
            var textElementsThisLine = 0;
            while(enumerator.MoveNext())
            {
                textElementsThisLine++;
                result.Append(enumerator.GetTextElement());
                if(textElementsThisLine == charsOnLine)
                {
                    result.Append('\n');
                    newLinesAt.Add(enumerator.ElementIndex + newLinesAt.Count + 1);
                    textElementsThisLine = 0;
                }
            }
            textLayout.Text = result.ToString();

            var foregroundColors = specialForegrounds != null ? specialForegrounds.ToDictionary(x => x.Key + x.Key / charsOnLine, x => x.Value) : new Dictionary<int, Color>();
            var backgroundColors = specialBackgrounds != null ? specialBackgrounds.ToDictionary(x => x.Key + x.Key / charsOnLine, x => x.Value) : new Dictionary<int, Color>();
            if(selectedArea != default(Rectangle))
            {
                var textWithNewLines = textLayout.Text;

                var startRow = (int)Math.Min(newLinesAt.Count - 1, Math.Floor(selectedArea.Y / lineSize.Height));
                var endRow = (int)Math.Min(newLinesAt.Count - 1, Math.Floor((selectedArea.Y + selectedArea.Height) / lineSize.Height));
                var startColumn = (int)Math.Round(selectedArea.X / charWidth);
                var endColumn = (int)Math.Round((selectedArea.X + selectedArea.Width) / charWidth);

                if(selectionMode == SelectionMode.Block)
                {
                    for(var i = startRow; i <= endRow; i++)
                    {
                        for(var j = startColumn; j <= endColumn; j++)
                        {
                            foregroundColors[(charsOnLine + 1) * i + j] = GetSelectionForegroundColor(i);
                            backgroundColors[(charsOnLine + 1) * i + j] = selectionColor;
                        }
                    }
                }
                else
                {
                    if(selectionDirection == SelectionDirection.NW)
                    {
                        Utilities.Swap(ref startColumn, ref endColumn);
                        Utilities.Swap(ref startRow, ref endRow);
                    }

                    var startIndex = startColumn + newLinesAt[startRow];
                    var endIndex = endColumn + newLinesAt[endRow];

                    if(endIndex < startIndex)
                    {
                        Utilities.Swap(ref startIndex, ref endIndex);
                    }

                    var textWithNewLinesStringInfo = new StringInfo(textWithNewLines);
                    startIndex = Math.Max(0, Math.Min(textWithNewLinesStringInfo.LengthInTextElements - 1, startIndex));
                    endIndex = Math.Max(0, Math.Min(textWithNewLinesStringInfo.LengthInTextElements - 1, endIndex));

                    for(var i = startIndex; i <= endIndex; i++)
                    {
                        foregroundColors[i] = GetSelectionForegroundColor(i);
                        backgroundColors[i] = selectionColor;
                    }
                    selectedContent = textWithNewLinesStringInfo.SubstringByTextElements(startIndex, endIndex - startIndex + 1);
                }
            }
            else
            {
                selectedContent = null;
            }

            foreach(var entry in GetColorRanges(foregroundColors))
            {
                textLayout.SetForeground(entry.Item3, entry.Item1, entry.Item2);
            }
            foreach(var entry in GetColorRanges(backgroundColors))
            {
                textLayout.SetBackground(entry.Item3, entry.Item1, entry.Item2);
            }

            ctx.DrawTextLayout(textLayout, 0, 0);
            textLayout.ClearAttributes();
        }

        public void ResetSelection()
        {
            selectedContent = null;
        }

        public void DrawCursor(Context ctx, int offset, bool focused)
        {
            var column = offset % MaxOffset;
            var row = offset / MaxOffset;
            ctx.SetColor(defaultForeground);
            ctx.Rectangle(new Rectangle(column * charWidth, row * lineSize.Height, charWidth, lineSize.Height));
            if(focused)
            {
                ctx.Fill();
            }
            else
            {
                ctx.Stroke();
            }
        }

        public void FillClipboardData(ClipboardData data)
        {
            if(selectedContent != null)
            {
                data.AppendText(selectedContent);
            }
        }

        public void Erase(int from, int to, Color? background = null)
        {
            var builder = new StringBuilder();
            to = Math.Max(0, Math.Min(to, content.Length - 1));

            var stringInfo = new StringInfo(content);
            if(from > 0)
            {
                builder.Append(stringInfo.SubstringByTextElements(0, from));<commit_msg>Check whether previous row content is not empty.<commit_after>﻿//
// Copyright (c) Antmicro
//
// This file is part of the Emul8 project.
// Full license details are defined in the 'LICENSE' file.
//
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using Terminal.Misc;
using Xwt;
using Xwt.Drawing;

namespace Terminal.Rows
{
    public class MonospaceTextRow : IRow
    {
        public MonospaceTextRow(string content)
        {
#if DEBUG
            if(content.Contains("\n"))
            {
                throw new ArgumentException("Content cannot contain a newline character.");
            }
#endif
            this.content = content;
            lengthInTextElements = new StringInfo(content).LengthInTextElements;
        }

        public double PrepareForDrawing(ILayoutParameters parameters)
        {
            defaultForeground = parameters.DefaultForeground;
            selectionColor = parameters.SelectionColor;
            textLayout = TextLayoutCache.GetValue(parameters);
            lineSize = LineSizeCache.GetValue(parameters);
            charWidth = CharSizeCache.GetValue(parameters).Width;
            MaxOffset = (int)(lineSize.Width / charWidth);
            return lineSize.Height * Math.Ceiling((lengthInTextElements == 0 ? 1 : lengthInTextElements) * charWidth / lineSize.Width);
        }

        public void Draw(Context ctx, Rectangle selectedArea, SelectionDirection selectionDirection, SelectionMode selectionMode)
        {
            ctx.SetColor(defaultForeground);
            var newLinesAt = new List<int> { 0 };
            var charsOnLine = (int)Math.Floor(lineSize.Width / charWidth);

            var result = new StringBuilder();
            var enumerator = StringInfo.GetTextElementEnumerator(content);
            var textElementsThisLine = 0;
            while(enumerator.MoveNext())
            {
                textElementsThisLine++;
                result.Append(enumerator.GetTextElement());
                if(textElementsThisLine == charsOnLine)
                {
                    result.Append('\n');
                    newLinesAt.Add(enumerator.ElementIndex + newLinesAt.Count + 1);
                    textElementsThisLine = 0;
                }
            }
            textLayout.Text = result.ToString();

            var foregroundColors = specialForegrounds != null ? specialForegrounds.ToDictionary(x => x.Key + x.Key / charsOnLine, x => x.Value) : new Dictionary<int, Color>();
            var backgroundColors = specialBackgrounds != null ? specialBackgrounds.ToDictionary(x => x.Key + x.Key / charsOnLine, x => x.Value) : new Dictionary<int, Color>();
            if(selectedArea != default(Rectangle))
            {
                var textWithNewLines = textLayout.Text;

                var startRow = (int)Math.Min(newLinesAt.Count - 1, Math.Floor(selectedArea.Y / lineSize.Height));
                var endRow = (int)Math.Min(newLinesAt.Count - 1, Math.Floor((selectedArea.Y + selectedArea.Height) / lineSize.Height));
                var startColumn = (int)Math.Round(selectedArea.X / charWidth);
                var endColumn = (int)Math.Round((selectedArea.X + selectedArea.Width) / charWidth);

                if(selectionMode == SelectionMode.Block)
                {
                    for(var i = startRow; i <= endRow; i++)
                    {
                        for(var j = startColumn; j <= endColumn; j++)
                        {
                            foregroundColors[(charsOnLine + 1) * i + j] = GetSelectionForegroundColor(i);
                            backgroundColors[(charsOnLine + 1) * i + j] = selectionColor;
                        }
                    }
                }
                else
                {
                    if(selectionDirection == SelectionDirection.NW)
                    {
                        Utilities.Swap(ref startColumn, ref endColumn);
                        Utilities.Swap(ref startRow, ref endRow);
                    }

                    var startIndex = startColumn + newLinesAt[startRow];
                    var endIndex = endColumn + newLinesAt[endRow];

                    if(endIndex < startIndex)
                    {
                        Utilities.Swap(ref startIndex, ref endIndex);
                    }

                    var textWithNewLinesStringInfo = new StringInfo(textWithNewLines);
                    startIndex = Math.Max(0, Math.Min(textWithNewLinesStringInfo.LengthInTextElements - 1, startIndex));
                    endIndex = Math.Max(0, Math.Min(textWithNewLinesStringInfo.LengthInTextElements - 1, endIndex));

                    for(var i = startIndex; i <= endIndex; i++)
                    {
                        foregroundColors[i] = GetSelectionForegroundColor(i);
                        backgroundColors[i] = selectionColor;
                    }
                    selectedContent = textWithNewLinesStringInfo.SubstringByTextElements(startIndex, endIndex - startIndex + 1);
                }
            }
            else
            {
                selectedContent = null;
            }

            foreach(var entry in GetColorRanges(foregroundColors))
            {
                textLayout.SetForeground(entry.Item3, entry.Item1, entry.Item2);
            }
            foreach(var entry in GetColorRanges(backgroundColors))
            {
                textLayout.SetBackground(entry.Item3, entry.Item1, entry.Item2);
            }

            ctx.DrawTextLayout(textLayout, 0, 0);
            textLayout.ClearAttributes();
        }

        public void ResetSelection()
        {
            selectedContent = null;
        }

        public void DrawCursor(Context ctx, int offset, bool focused)
        {
            var column = offset % MaxOffset;
            var row = offset / MaxOffset;
            ctx.SetColor(defaultForeground);
            ctx.Rectangle(new Rectangle(column * charWidth, row * lineSize.Height, charWidth, lineSize.Height));
            if(focused)
            {
                ctx.Fill();
            }
            else
            {
                ctx.Stroke();
            }
        }

        public void FillClipboardData(ClipboardData data)
        {
            if(selectedContent != null)
            {
                data.AppendText(selectedContent);
            }
        }

        public void Erase(int from, int to, Color? background = null)
        {
            var builder = new StringBuilder();
            to = Math.Max(0, Math.Min(to, content.Length - 1));

            var stringInfo = new StringInfo(content);
            if(from > 0 && stringInfo.LengthInTextElements > 0)
            {
                builder.Append(stringInfo.SubstringByTextElements(0, from));
{'fraction_non_alphanumeric': 0.09046004128575641, 'fraction_numerical': 0.004202300206428782, 'mean_word_length': 1.646312914553258, 'pattern_counts': {'":': 0, '<': 17, '<?xml version=': 0, '>': 20, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1745392', 'n_tokens_mistral': 3457, 'n_tokens_neox': 3273, 'n_words': 708}