Skip to main content
Tweeted twitter.com/StackCodeReview/status/982956383552393216
edited title, quoted non-c# code, corrected punctuation
Source Link
t3chb0t
  • 44.7k
  • 9
  • 85
  • 191

Simple console text editor in C#

The method SplitLineSplitLine was a head scratcher (really showcased the terseness of Ruby) where his line splitting and new carriage code looks like and I couldntcouldn't come up with anything like it in C#.

lines[row..row] = [line[0...col],line[col..-1]]
lines[row..row] = [line[0...col],line[col..-1]]

Simple text editor in C#

The method SplitLine was a head scratcher (really showcased the terseness of Ruby) where his line splitting and new carriage code looks like and I couldnt come up with anything like it in C#

lines[row..row] = [line[0...col],line[col..-1]]

Simple console text editor

The method SplitLine was a head scratcher (really showcased the terseness of Ruby) where his line splitting and new carriage code looks like and I couldn't come up with anything like it in C#.

lines[row..row] = [line[0...col],line[col..-1]]
added 992 characters in body; edited tags; edited title
Source Link
200_success
  • 145.7k
  • 22
  • 191
  • 481

Simple Text Editortext editor in C#

I have been following along Gary BernhardtsBernhardt's excellent video series on "Building a Text Editor From Scratch". It's in Ruby but I wanted to do it in C# just to see how much it differs.

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;

namespace TextEditor
{
 class Program
{
    static void Main(string[] args)
    {
        new Editor().Run();
    }
}

class Editor
{
    Buffer _buffer;
    Cursor _cursor;
    Stack<object> _history;

    public Editor()
    {
        var lines = File.ReadAllLines("foo.txt")
                        .Where(x => x != Environment.NewLine);

        _buffer = new Buffer(lines);
        _cursor = new Cursor();
        _history = new Stack<object>();
    }

    public void Run()Program
    {
        whilestatic void Main(truestring[] args)
        {
            Rendernew Editor();
            HandleInput.Run();
        }
    }

    private voidclass HandleInput()Editor
    {
        varBuffer character_buffer;
 = Console.ReadKey();      Cursor _cursor;
        Stack<object> _history;

        ifpublic (Editor(ConsoleModifiers.Control & character.Modifiers) != 0 && 
              character.Key == ConsoleKey.Q)
        {
            Environmentvar lines = File.ExitReadAllLines(0"foo.txt");
        }                    .Where(x => x != Environment.NewLine);

        else if ((ConsoleModifiers.Control & character.Modifiers)_buffer != 0new &&Buffer(lines);
             _cursor character.Key= ==new ConsoleKey.PCursor()
        {;
            _cursor_history = _cursor.Upnew Stack<object>(_buffer);
        }

        elsepublic ifvoid (Run(ConsoleModifiers.Control & character.Modifiers) != 0 &&
              character.Key == ConsoleKey.N)
        {
            _cursorwhile =(true)
 _cursor.Down           {
                Render(_buffer);
                HandleInput();
            }
        }

        elseprivate ifvoid (HandleInput(ConsoleModifiers.Control & character.Modifiers) != 0 &&
              character.Key == ConsoleKey.B)
        {
            _cursorvar character = _cursorConsole.LeftReadKey(_buffer);
        }  

        else    if ((ConsoleModifiers.Control & character.Modifiers) != 0 && 
                  character.Key == ConsoleKey.ZQ)
            {
            _cursor = _cursor  Environment.RightExit(_buffer0);
            }

            else if ((ConsoleModifiers.Control & character.Modifiers) != 0 &&
                  character.Key == ConsoleKey.UP)
            {
            RestoreSnapshot    _cursor = _cursor.Up(_buffer);
            }

            else if (character(ConsoleModifiers.KeyControl ==& ConsoleKeycharacter.BackspaceModifiers)
  != 0 &&
     {
            if (_cursorcharacter.ColKey >== 0ConsoleKey.N)
            {
                SaveSnapshot_cursor = _cursor.Down(_buffer);
            }

    _buffer = _buffer.Delete      else if (_cursor(ConsoleModifiers.Row,Control _cursor& character.ColModifiers) -!= 10 &&
                  character.Key == ConsoleKey.B);
            {
                _cursor = _cursor.Left(_buffer);
            }
        }

            else if (character(ConsoleModifiers.KeyControl ==& ConsoleKeycharacter.EnterModifiers) != 0 &&
        {
          character.Key == SaveSnapshot(ConsoleKey.Z);
            _buffer{
 = _buffer.SplitLine(_cursor.Row, _cursor.Col);
             _cursor = _cursor.DownRight(_buffer).MoveToCol(0);
            }

        else
    else if ((ConsoleModifiers.Control & {character.Modifiers) != 0 &&
            SaveSnapshot();
     character.Key == ConsoleKey.U)
     _buffer = _buffer.Insert(character.KeyChar.ToString(), _cursor.Row, _cursor.Col);   {
            _cursor = _cursor.Right  RestoreSnapshot(_buffer);
            }

            else if (character.Key == ConsoleKey.Backspace)
            {
                if (_cursor.Col > 0)
                {
                    SaveSnapshot();
                    _buffer = _buffer.Delete(_cursor.Row, _cursor.Col - 1);
                    _cursor = _cursor.Left(_buffer);
                }
            }

    private void Render      else if(character.Key == ConsoleKey.Enter)
            {
        ANSI.ClearScreen        SaveSnapshot();
        ANSI.MoveCursor(0, 0);
       _buffer = _buffer.RenderSplitLine(_cursor.Row, _cursor.Col);
        ANSI.MoveCursor(        _cursor.Row, = _cursor.ColDown(_buffer).MoveToCol(0);
    }        }

    private void       else
            {
                SaveSnapshot();
    {
        _history    _buffer = _buffer.PushInsert(character.KeyChar.ToString(), _cursor.Row, _cursor.Col);
        _history        _cursor = _cursor.PushRight(_buffer);
            }

    private void RestoreSnapshot()
    {
        if( _history.Count > 0 )
        {
            _buffer = (Buffer)_history.Pop();
            _cursor = (Cursor)_history.Pop();
        }
    }
}

class Buffer       private void Render()
        {
    string[] _lines;       ANSI.ClearScreen();
            ANSI.MoveCursor(0, 0);
            _buffer.Render();
            ANSI.MoveCursor(_cursor.Row, _cursor.Col);
        }       

    public Buffer(IEnumerable<string> lines  private void SaveSnapshot()
        {
        _lines = lines  _history.ToArrayPush(_cursor);
            _history.Push(_buffer);
        }

    public void Render()
    {
       private foreachvoid RestoreSnapshot(var line in _lines)
        {
            Consoleif( _history.WriteLineCount > 0 )
            {
                _buffer = (lineBuffer)_history.Pop();
                _cursor = (Cursor)_history.Pop();
            }
        }
    }

    public intclass LineCount()Buffer
    {
        return _lines.Count();
   string[] }_lines;

    public int LineLength  public Buffer(intIEnumerable<string> rowlines)
        {
        return _lines[row]   _lines = lines.Length;ToArray();
        }

    internal Buffer Insert(string character, int row,public intvoid colRender()
        {
        var linesDeepCopy = _lines.Select(x =>foreach x).ToArray(var line in _lines);
        linesDeepCopy[row] = linesDeepCopy[row].Insert(col, character); {
        return new Buffer      Console.WriteLine(linesDeepCopyline);
            }
        }

    internal Buffer Delete(int row, public int colLineCount()
    {
        var linesDeepCopy ={
 _lines.Select(x => x).ToArray();
        linesDeepCopy[row] =return linesDeepCopy[row]_lines.RemoveCount(col, 1);
        return new Buffer(linesDeepCopy);
    }

    internal Buffer SplitLine(int row, public int colLineLength(int row)
        {
        var linesDeepCopy = _lines.Select(x =>return x)_lines[row].ToList();Length;
        }

        internal Buffer Insert(string character, int row, int col)
        {
            var linelinesDeepCopy = linesDeepCopy[row];_lines.Select(x => x).ToArray();
            linesDeepCopy[row] = linesDeepCopy[row].Insert(col, character);
            return new Buffer(linesDeepCopy);
        }

        varinternal newLinesBuffer =Delete(int newrow, []int col)
        { 
 line           var linesDeepCopy = _lines.SubstringSelect(0,x col),=> linex).SubstringToArray(col,);
 line.Length - line         linesDeepCopy[row] = linesDeepCopy[row].SubstringRemove(0col, col1).Length;
            return new Buffer(linesDeepCopy);
        };

        linesDeepCopy[row]internal =Buffer newLines[0];SplitLine(int row, int col)
        linesDeepCopy[row{
 + 1]          var linesDeepCopy = newLines[1];_lines.Select(x => x).ToList();

            var line = linesDeepCopy[row];

            var newLines = new [] { line.Substring(0, col), line.Substring(col, line.Length - line.Substring(0, col).Length) };

        return new Buffer(linesDeepCopy);
  linesDeepCopy[row] = }newLines[0];
}            linesDeepCopy[row + 1] = newLines[1];

class Cursor
{
    public int Row { get; set; }
    public int Col { get; set; }


    public Cursor(int row=0, int col=0)
    {
        Rowreturn =new row;Buffer(linesDeepCopy);
        Col = col;}
    }

    internalclass Cursor Up(Buffer buffer)
    {
        returnpublic newint Cursor(Row -{ 1,get; Col).Clamp(buffer);set; }
        public int Col { get; set; }
 

    internal Cursor Down  public Cursor(Bufferint bufferrow=0, int col=0)
        {
        return new Cursor(  Row += 1,row;
            Col).Clamp(buffer); = col;
    }
    }

        internal Cursor LeftUp(Buffer buffer)
        {
            return new Cursor(Row, Col - 1, Col).Clamp(buffer);
        }

        internal Cursor RightDown(Buffer buffer)
        {
            return new Cursor(Row, Col + 1, Col).Clamp(buffer);
        }
        

    private    internal Cursor ClampLeft(Buffer buffer)
        {
        Row = Math.Min(buffer.LineCount() - 1return ,new Math.MaxCursor(Row, 0));
        Col =- Math.Min(buffer.LineLength(Row1), Math.MaxClamp(Col, 0)buffer);
        return new Cursor(Row, Col);
    }

        internal Cursor MoveToColRight(intBuffer colbuffer)
        {
            return new Cursor(Row, 0Col + 1).Clamp(buffer);
    }
    }

class ANSI       private Cursor Clamp(Buffer buffer)
        {
    public static void ClearScreen     Row = Math.Min(buffer.LineCount() - 1 , Math.Max(Row, 0));
            Col = Math.Min(buffer.LineLength(Row), Math.Max(Col, 0));
            return new Cursor(Row, Col);
        }

        internal Cursor MoveToCol(int col)
        {
        Console.Clear    return new Cursor(Row, 0);
        }
    }

    public static void MoveCursor(int row, intclass col)ANSI
    {
        public static void ClearScreen()
        {
            Console.Clear();
        }

        public static void MoveCursor(int row, int col)
        {
            Console.CursorTop = row;
            Console.CursorLeft = col;
        }
    }
}

}

Simple Text Editor in C#

I have been following along Gary Bernhardts excellent video series on "Building a Text Editor From Scratch". It's in Ruby but I wanted to do it in C# just to see how much it differs.

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;

namespace TextEditor
{
 class Program
{
    static void Main(string[] args)
    {
        new Editor().Run();
    }
}

class Editor
{
    Buffer _buffer;
    Cursor _cursor;
    Stack<object> _history;

    public Editor()
    {
        var lines = File.ReadAllLines("foo.txt")
                        .Where(x => x != Environment.NewLine);

        _buffer = new Buffer(lines);
        _cursor = new Cursor();
        _history = new Stack<object>();
    }

    public void Run()
    {
        while (true)
        {
            Render();
            HandleInput();
        }
    }

    private void HandleInput()
    {
        var character = Console.ReadKey();
      

        if ((ConsoleModifiers.Control & character.Modifiers) != 0 && 
              character.Key == ConsoleKey.Q)
        {
            Environment.Exit(0);
        }

        else if ((ConsoleModifiers.Control & character.Modifiers) != 0 &&
              character.Key == ConsoleKey.P)
        {
            _cursor = _cursor.Up(_buffer);
        }

        else if ((ConsoleModifiers.Control & character.Modifiers) != 0 &&
              character.Key == ConsoleKey.N)
        {
            _cursor = _cursor.Down(_buffer);
        }

        else if ((ConsoleModifiers.Control & character.Modifiers) != 0 &&
              character.Key == ConsoleKey.B)
        {
            _cursor = _cursor.Left(_buffer);
        }

        else if ((ConsoleModifiers.Control & character.Modifiers) != 0 &&
              character.Key == ConsoleKey.Z)
        {
            _cursor = _cursor.Right(_buffer);
        }

        else if ((ConsoleModifiers.Control & character.Modifiers) != 0 &&
             character.Key == ConsoleKey.U)
        {
            RestoreSnapshot();
        }

        else if (character.Key == ConsoleKey.Backspace)
         {
            if (_cursor.Col > 0)
            {
                SaveSnapshot();
                _buffer = _buffer.Delete(_cursor.Row, _cursor.Col - 1);
                _cursor = _cursor.Left(_buffer);
            }
        }

        else if(character.Key == ConsoleKey.Enter)
        {
            SaveSnapshot();
            _buffer = _buffer.SplitLine(_cursor.Row, _cursor.Col);
            _cursor = _cursor.Down(_buffer).MoveToCol(0);
        }

        else
        {
            SaveSnapshot();
            _buffer = _buffer.Insert(character.KeyChar.ToString(), _cursor.Row, _cursor.Col);
            _cursor = _cursor.Right(_buffer);
        }

        
    }

    private void Render()
    {
        ANSI.ClearScreen();
        ANSI.MoveCursor(0, 0);
        _buffer.Render();
        ANSI.MoveCursor(_cursor.Row, _cursor.Col);
    }       

    private void SaveSnapshot()
    {
        _history.Push(_cursor);
        _history.Push(_buffer);
    }

    private void RestoreSnapshot()
    {
        if( _history.Count > 0 )
        {
            _buffer = (Buffer)_history.Pop();
            _cursor = (Cursor)_history.Pop();
        }
    }
}

class Buffer
{
    string[] _lines;

    public Buffer(IEnumerable<string> lines)
    {
        _lines = lines.ToArray();
    }

    public void Render()
    {
        foreach (var line in _lines)
        {
            Console.WriteLine(line);
        }
    }

    public int LineCount()
    {
        return _lines.Count();
    }

    public int LineLength(int row)
    {
        return _lines[row].Length;
    }

    internal Buffer Insert(string character, int row, int col)
    {
        var linesDeepCopy = _lines.Select(x => x).ToArray();
        linesDeepCopy[row] = linesDeepCopy[row].Insert(col, character);
        return new Buffer(linesDeepCopy);
    }

    internal Buffer Delete(int row, int col)
    {
        var linesDeepCopy = _lines.Select(x => x).ToArray();
        linesDeepCopy[row] = linesDeepCopy[row].Remove(col, 1);
        return new Buffer(linesDeepCopy);
    }

    internal Buffer SplitLine(int row, int col)
    {
        var linesDeepCopy = _lines.Select(x => x).ToList();

        var line = linesDeepCopy[row];

        var newLines = new [] { line.Substring(0, col), line.Substring(col, line.Length - line.Substring(0, col).Length) };

        linesDeepCopy[row] = newLines[0];
        linesDeepCopy[row + 1] = newLines[1];



        return new Buffer(linesDeepCopy);
    }
}

class Cursor
{
    public int Row { get; set; }
    public int Col { get; set; }


    public Cursor(int row=0, int col=0)
    {
        Row = row;
        Col = col;
    }

    internal Cursor Up(Buffer buffer)
    {
        return new Cursor(Row - 1, Col).Clamp(buffer);
    }

    internal Cursor Down(Buffer buffer)
    {
        return new Cursor(Row + 1, Col).Clamp(buffer);
    }
    

    internal Cursor Left(Buffer buffer)
    {
        return new Cursor(Row, Col - 1).Clamp(buffer);
    }

    internal Cursor Right(Buffer buffer)
    {
        return new Cursor(Row, Col + 1).Clamp(buffer);
    }

    private Cursor Clamp(Buffer buffer)
    {
        Row = Math.Min(buffer.LineCount() - 1 , Math.Max(Row, 0));
        Col = Math.Min(buffer.LineLength(Row), Math.Max(Col, 0));
        return new Cursor(Row, Col);
    }

    internal Cursor MoveToCol(int col)
    {
        return new Cursor(Row, 0);
    }
}

class ANSI
{
    public static void ClearScreen()
    {
        Console.Clear();
    }

    public static void MoveCursor(int row, int col)
    {
        Console.CursorTop = row;
        Console.CursorLeft = col;
    }
}

}

Simple text editor in C#

I have been following along Gary Bernhardt's excellent video series on "Building a Text Editor From Scratch". It's in Ruby but I wanted to do it in C# just to see how much it differs.

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;

namespace TextEditor
{
    class Program
    {
        static void Main(string[] args)
        {
            new Editor().Run();
        }
    }

    class Editor
    {
        Buffer _buffer;
        Cursor _cursor;
        Stack<object> _history;

        public Editor()
        {
            var lines = File.ReadAllLines("foo.txt")
                            .Where(x => x != Environment.NewLine);

            _buffer = new Buffer(lines);
            _cursor = new Cursor();
            _history = new Stack<object>();
        }

        public void Run()
        {
            while (true)
            {
                Render();
                HandleInput();
            }
        }

        private void HandleInput()
        {
            var character = Console.ReadKey();
          

            if ((ConsoleModifiers.Control & character.Modifiers) != 0 && 
                  character.Key == ConsoleKey.Q)
            {
                Environment.Exit(0);
            }

            else if ((ConsoleModifiers.Control & character.Modifiers) != 0 &&
                  character.Key == ConsoleKey.P)
            {
                _cursor = _cursor.Up(_buffer);
            }

            else if ((ConsoleModifiers.Control & character.Modifiers) != 0 &&
                  character.Key == ConsoleKey.N)
            {
                _cursor = _cursor.Down(_buffer);
            }

            else if ((ConsoleModifiers.Control & character.Modifiers) != 0 &&
                  character.Key == ConsoleKey.B)
            {
                _cursor = _cursor.Left(_buffer);
            }

            else if ((ConsoleModifiers.Control & character.Modifiers) != 0 &&
                  character.Key == ConsoleKey.Z)
            {
                _cursor = _cursor.Right(_buffer);
            }

            else if ((ConsoleModifiers.Control & character.Modifiers) != 0 &&
                 character.Key == ConsoleKey.U)
            {
                RestoreSnapshot();
            }

            else if (character.Key == ConsoleKey.Backspace)
            {
                if (_cursor.Col > 0)
                {
                    SaveSnapshot();
                    _buffer = _buffer.Delete(_cursor.Row, _cursor.Col - 1);
                    _cursor = _cursor.Left(_buffer);
                }
            }

            else if(character.Key == ConsoleKey.Enter)
            {
                SaveSnapshot();
                _buffer = _buffer.SplitLine(_cursor.Row, _cursor.Col);
                _cursor = _cursor.Down(_buffer).MoveToCol(0);
            }

            else
            {
                SaveSnapshot();
                _buffer = _buffer.Insert(character.KeyChar.ToString(), _cursor.Row, _cursor.Col);
                _cursor = _cursor.Right(_buffer);
            }

            
        }

        private void Render()
        {
            ANSI.ClearScreen();
            ANSI.MoveCursor(0, 0);
            _buffer.Render();
            ANSI.MoveCursor(_cursor.Row, _cursor.Col);
        }       

        private void SaveSnapshot()
        {
            _history.Push(_cursor);
            _history.Push(_buffer);
        }

        private void RestoreSnapshot()
        {
            if( _history.Count > 0 )
            {
                _buffer = (Buffer)_history.Pop();
                _cursor = (Cursor)_history.Pop();
            }
        }
    }

    class Buffer
    {
        string[] _lines;

        public Buffer(IEnumerable<string> lines)
        {
            _lines = lines.ToArray();
        }

        public void Render()
        {
            foreach (var line in _lines)
            {
                Console.WriteLine(line);
            }
        }

        public int LineCount()
        {
            return _lines.Count();
        }

        public int LineLength(int row)
        {
            return _lines[row].Length;
        }

        internal Buffer Insert(string character, int row, int col)
        {
            var linesDeepCopy = _lines.Select(x => x).ToArray();
            linesDeepCopy[row] = linesDeepCopy[row].Insert(col, character);
            return new Buffer(linesDeepCopy);
        }

        internal Buffer Delete(int row, int col)
        { 
            var linesDeepCopy = _lines.Select(x => x).ToArray();
            linesDeepCopy[row] = linesDeepCopy[row].Remove(col, 1);
            return new Buffer(linesDeepCopy);
        }

        internal Buffer SplitLine(int row, int col)
        {
            var linesDeepCopy = _lines.Select(x => x).ToList();

            var line = linesDeepCopy[row];

            var newLines = new [] { line.Substring(0, col), line.Substring(col, line.Length - line.Substring(0, col).Length) };

            linesDeepCopy[row] = newLines[0];
            linesDeepCopy[row + 1] = newLines[1];



            return new Buffer(linesDeepCopy);
        }
    }

    class Cursor
    {
        public int Row { get; set; }
        public int Col { get; set; }
 

        public Cursor(int row=0, int col=0)
        {
            Row = row;
            Col = col;
        }

        internal Cursor Up(Buffer buffer)
        {
            return new Cursor(Row - 1, Col).Clamp(buffer);
        }

        internal Cursor Down(Buffer buffer)
        {
            return new Cursor(Row + 1, Col).Clamp(buffer);
        }
        

        internal Cursor Left(Buffer buffer)
        {
            return new Cursor(Row, Col - 1).Clamp(buffer);
        }

        internal Cursor Right(Buffer buffer)
        {
            return new Cursor(Row, Col + 1).Clamp(buffer);
        }

        private Cursor Clamp(Buffer buffer)
        {
            Row = Math.Min(buffer.LineCount() - 1 , Math.Max(Row, 0));
            Col = Math.Min(buffer.LineLength(Row), Math.Max(Col, 0));
            return new Cursor(Row, Col);
        }

        internal Cursor MoveToCol(int col)
        {
            return new Cursor(Row, 0);
        }
    }

    class ANSI
    {
        public static void ClearScreen()
        {
            Console.Clear();
        }

        public static void MoveCursor(int row, int col)
        {
            Console.CursorTop = row;
            Console.CursorLeft = col;
        }
    }
}
edited tags; added 1 character in body; added 1 character in body; deleted 1 character in body
Source Link
200_success
  • 145.7k
  • 22
  • 191
  • 481

I have been following along Gary Bernhardts excellent video series on "Building a Text Editor From Scratch". ItsIt's in Ruby but I wanted to do it in C# just to see how much it differs.

Implementation wise itsit's faithful to what he does. I do have questions whether the code is up to mark in terms of new C# conventions, haven't violated any biggies or gone overboard with LINQ.

The method SplitLine was a head scratchedscratcher ( reallyreally showcased the terseness of rubyRuby) where his line splitting and new carriage code looks like and I couldnt come up with anything like it in C#

I have been following along Gary Bernhardts excellent video series on "Building a Text Editor From Scratch". Its in Ruby but I wanted to do it in C# just to see how much it differs.

Implementation wise its faithful to what he does. I do have questions whether the code is up to mark in terms of new C# conventions, haven't violated any biggies or gone overboard with LINQ.

The method SplitLine was a head scratched ( really showcased the terseness of ruby) where his line splitting and new carriage code looks like and I couldnt come up with anything like it in C#

I have been following along Gary Bernhardts excellent video series on "Building a Text Editor From Scratch". It's in Ruby but I wanted to do it in C# just to see how much it differs.

Implementation wise it's faithful to what he does. I do have questions whether the code is up to mark in terms of new C# conventions, haven't violated any biggies or gone overboard with LINQ.

The method SplitLine was a head scratcher (really showcased the terseness of Ruby) where his line splitting and new carriage code looks like and I couldnt come up with anything like it in C#

Source Link
rustyocean
  • 173
  • 1
  • 3
Loading