Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / C#

Ynote Classic - Text and Source Code Editor

4.89/5 (8 votes)
31 Jul 2014GPL39 min read 40.5K  
A multi-purpose open source text editor and source code editor with syntax highlighting, code folding, auto indentation and much more

Image 1

Introduction

I started ynote as a project to learn the .NET Framework. The first ynote version consisted of nothing, just a TextBox control and some basic commands - Cut, Copy, etc. Then I saw the FastColoredTextBox control. The FastColoredTextBox control was first included in v2.0, supporting only 5 languages. Now, it has just everything a perfect code editor can have. Another reason was to know the capabilities of .NET because I didn't find any decent Text Editor written using the .NET Platform (not including C++) So I mae "Ynote Classic" - The Text Editor, coded with .NET.

Features

Ynote has a huge list of features which make it user friendly and interactive:

  • Syntax Highlighting, Code Folding and Auto Indentation for about 40 languages
  • Multiple Carets and Selections
  • Macro Recording and Playback to automate task
  • Extensible with Color Schemes, Scripts, Commands, Plugins and Custom Shortcuts
  • Split Screen, Full Screen and Distraction Free Editing
  • Powerful Search and Replace using Regular Expressions
  • Amazing Multi and Single Window Environment
  • Code Snippets to improve productivity
  • Document Map and Ruler

This is just a basic list of features, dig into it to learn more.

Using the Code

Syntax Highlighting

The heart of Ynote Classic is the FastColoredTextBox control which is used for Syntax Highlight, Auto Indentation and Code Folding. FastColoredTextBox uses Styles and adds them with the help of Regular Expressions to a TextBox range, which has a Start and End Place.

Ynote Highlight's code using its inbuilt highlighter can also be extended using ynotesyntax files.

Color Schemes

Ynote has support for various color schemes.

A color scheme is an XML document with the extension .ynotetheme which is used to style the syntax highlighting and the control.

A ynote has 2 main tags. The "Key" tag and the "Style" tag. Style tag is used to style the Syntax Highlighter and the Key tag is used to style the textArea.

The various styles are:

  • Comment
  • String
  • Keyword
  • Variable
  • Storage
  • Constant
  • TagName
  • TagBracket
  • AttributeName
  • AttributeValue
  • DoctypeDeclaration
  • CSSProperty
  • CSSPropertyValue
  • CSSSelector
  • Preprocessor
  • Punctuation
  • LibraryFunction
  • LibraryClass

The keys:

  • Background
  • Foreground
  • Caret
  • LineNumber
  • LineNumberPadding
  • CurrentLine
  • Selection
  • ServicesLine
  • Bookmark
  • FoldingIndication
  • SameWords
  • BracketStyle
  • BracketStyle2

How Does It Work?

See YnoteThemeReader.cs.

When ynote loads a theme file, the key values are parsed and assigned to the FastColoredTextBox.

See SyntaxHighlighter.cs. It has various public styles (from FastColoredTextBoxNS.Style) to which the values are assigned and the Syntax Highlighter uses that Style only. Like:

C#
public void HighlightSyntax(Range r)
{
    r.tb.CommentPrefix = "#";
    r.ClearStyle(Comment, String);
    r.SetStyle(Comment, @"#.*$", RegexOptions.Multiline)
    r.SetStyle(String, @"""""|@""""|''|@"".*?""|(?<!@)(?<range>"".*?[^\\]"")|'.*?[^\\]'")
}

Docking

Ynote Classic uses the DockPanelSuite for Docking with the VS2012 light theme.

Snippets

Ynote Classic has support for snippets which are loaded from a .ynotesnippet file. Each snippet has the following properties:

  • TabTrigger: Snippet will be called when the user presses tab after {TabTrigger}
  • Content: The content of the Snippet
  • Scope: The Scope of the Snippet (HTML, CSS, CSharp etc.)

Creating Snippets

Anyone can create a snippet for easy workflow. The syntax of a YnoteSnippet Content is:

  • ^: The Position of the Caret after inserting the Snippet
  • $selection: The Selected Text when the snippet was triggered
  • $current_line: The Text on current line when the snippet was triggered
  • $file_name: The name of the file being edited
  • $file_name_extension: The name of the file being edited with extension
  • $clipboard: The text on the Clipboard
  • $eol: Line Ending literal to get the current line ending
  • $choose_file: Loads an OpenFileDialog and replaces with the chosen file

Editing

Ynote can make editing a great experience for you. Some features include:

Multiple Carets/Selections

Use Ctrl+Click to add another caret or selection and start editing. Ynote does not support multiple carets on the same line for now.

Vertical/Column Selection

Use Alt+Drag or Alt+Shift+Arrow Keys to select an area and start editing text.

Split Editing

Split Editing is the best way to make use of your wide-screen monitor. Ynote supports Split Editing with Dockable Windows. You can split-edit a file by -

  • View -> Split -> Split Below - Splits the document below the active document
  • View -> Split -> Split Beside - Splits the document beside the active document
  • View -> Split -> Split Synchronized Scroll - Splits the document synchronizing the scrolling

Ynote Split Edit

Split Editing in Ynote

Search/Replace

Ynote has powerful search and replace capabilities. It supports "Find Next", "Find Previous", "Find In Folder", "Find in Project", and "Incremental Search" with regular expressions.

It can also find a character using Alt+F+{char}.

Image 3

Ynote Incremental Search ( Regex )

Macros

Ynote uses FastColoredTextBox's technique for recording and executing macros by storing the Key's Pressed.

A Ynote Macro is stored with .ynotemacro extension anywhere in the $ynotedata\ directory.

Recording a Macro

A Macro can be recorded by pressing Ctrl+M and performing some actions.

NOTE: Mouse Actions are not recorded in macros

Use Ctrl+M to Stop Recording Macro

Executing a Macro

Use can playback a macro using Ctrl+E.

You can also save the macro for execution later. It should be saved in the $ynotedata\ directory with the extension .ynotemacro.

Macro Shortcuts

So you want a shortcut to execute a macro? Ynote can do that. Create a file named User.ynotekeys in $ynotedata directory.

You can type shortcuts in the form of YnoteCommands Line-By-Line. Example (my User.ynotekeys):

Ctrl+Shift+Q=Macro:AddLineBefore
Ctrl+Shfit+M=Script:ColorPicker

You need to enter the command as it appears in the Commander. It can contain any Command. The Shortcuts should be separated by a newline(\r\n).

Scripting

Why I like ynote a lot is due to Scripting. Scripting has been possible using the CSScript library.

Scripts are stored in Ynote as .ys files. In ynote, Scripting has been used in:

  • Ynote Commands (Commander) - in $ynotedata\Commands Directory
  • Ynote Scripts - in $ynotedata\Scripts Directory
  • RunScripts Tasks - in $ynotedata\RunScripts\Tasks
  • Context Menu - in $ynotedata\ContextMenu.ys

Scripts are compiled to a .ysc file for faster execution.

The Commander

Ynote Commander is a tool which keeps all the useful commands at your finger tips. Just use Ctrl+Shift+P and Commander will popup. Begin typing anything you want.

Image 4

Using the Commander

Custom Commands

Ynote Supports adding custom commands from $ynotedata\Commands Directory.

A Ynote Command is a C# Script with the .ynotecommand extension. It contains a method GetCommand with a parameter IYnote. When called, it should return an instance of the ICommand interface.

C#
namespace SS.Ynote.Classic
{
    /// <summary>
    ///     A Ynote Command which when executed
    ///     is stored in a YnoteCommand
    /// </summary>
    public interface ICommand
    {
        /// <summary>
        ///     Command Key
        /// </summary>
        string Key { get; }

        /// <summary>
        ///     Possible Commands
        /// </summary>
        string[] Commands { get; }

        /// <summary>
        ///     Processes Command
        /// </summary>
        /// <param name="val"></param>
        /// <param name="ynote"></param>
        void ProcessCommand(string val, IYnote ynote);
    }
}
  • Key - The Key is the Class of the Command e.g., - In the Command SetSyntax:CSharp, SetSyntax is the Key and CSharp is the value.
  • Commands - List of Possible Commands (Used for Autocompletion)
  • ProcessCommand(string,IYnote) - Processes the Command with the Value val.

Build System (RunScripts)

Ynote uses RunScripts which are in JSON format as Build Systems. Each RunScript can invoke one or more Tasks. Example RunScript:

JavaScript
// Run Script to Run a python file
{
  // Path of the task and arguments (task specific) from $ynotedata directory
  "RunScripts\\Tasks\\Cmd": [
    "python",
    "$source"
  ]
}

Run Using Commander->Run:{runscript name}

This RunScript Invokes the Task Cmd.runtask stored in $ynotedata\RunScripts\Tasks\ directory.

You can add unlimited tasks one after the another and they will invoke one by one.

Variables
  • $source - The Active File being edited
  • $source_dir - The Directory of the Active File being edited
  • $source_name - The Name of the Active File being edited
  • $source_extension - The Extension of Active File being edited
  • $project_dir - The Directory of the currently Open Project
  • $project_name - The Name of the currently Open Project

Custom Tasks

A Ynote Task is nothing other than just a piece of C# code.

It should contain the RunTask method with a string array as arguments. Example:

C#
// RunScript Task to Create A Directory
using System.IO;

// Cmd Run Script Task
public void RunTask(string[] arguments)
{
    if(arguments.Length == 0)
        return;
    string dir = arguments[0];
    if(!Directory.Exists(dir))
        Directory.CreateDirectory(dir);
}

RunTasks are stored in the $ynotedata\RunScripts\Tasks directory with the .runtask extension. You can store it in any directory but in $ynotedata.

Symbol List

This was a challenge for me. I thought it would make my program huge. But then, I thought about the idea to use Regular Expressions. It made my task easier. This is what ynote does. It matches text with regexes to get list of functions/classes, etc.

The Regexes are fully customizable. Located in $ynotedata\Symbols.json.

Symbols.json (preview)

JavaScript
{
  "CSharp": {
    "Pattern": "\\b(class|struct|enum|interface|void)\\s+(?<range>\\w+?)\\b",
    "Options": 0
  },
  "C": {
    "Pattern": "\\b(class|struct|enum|interface|void|int|bool)\\s+(?<range>\\w+?)\\b",
    "Options": 0
  },
  "CPP": {
    "Pattern": "\\b(class|struct|enum|interface|void|int|bool)\\s+(?<range>\\w+?)\\b",
    "Options": 0
  },
  "VB": {
    "Pattern": "\\b(Class|Sub|Interface)\\s+(?<range>\\w+?)\\b",
    "Options": 0nn
  },
  "D": {

Key Bindings

Ynote uses .ynotekeys files for storing KeyBindings. Its format is:

{Key}:{Command}

* They are separated by a newline character.

Editor.ynotekeys

The Editor keybindings are the keybindings of the FastColoredTextBox control. It can be edited using the HotKeys Editor or opening Editor.ynotekeys from $ynotedata\Editor.ynotekeys directory.

User.ynotekeys

The User.ynotekeys file does not exist by default. It can be created using the Tools->User Keys menu. It executes YnoteCommands found in the Commander. e.g.:

Ctrl+Shift+K=Script:ColorPicker

When you press Ctrl+Shift+K, it executes ColorPicker.ys, which shows a color picker and inserts the color selected.

Packages

A Ynote Package is an archive with an index file. It contains resource files for extending ynote like:

  • Plugin
  • Color Scheme
  • YnoteScript
  • Snippet
  • RunScript
  • RunScript Task
  • YnoteCommand
  • Syntax File
  • Macros
  • ContextMenu and much more..

How does a package work?

A ynote package file is a zip file and has all the required files in the root directory with an index file. The index file contains information that where a file will go once it is installed. When installing a package, the first file which is extracted is the index file. Ynote uses ZipStorer to manage zip files.The following code generates a dictionary where a file will go.

C#
internal static IDictionary<string, string> GenerateDictionary(string manifest)
{
    IDictionary<string,string> dic = new Dictionary<string,string>();
    string[] lines = File.ReadAllLines(manifest);
    foreach (var line in lines)
    {
        var command = YnoteCommand.FromString(line);
        command.Value = command.Value.Replace("$ynotedata", GlobalSettings.SettingsDir);
        if (command.Value.IndexOf("$ynotedir") != -1)
            command.Value = command.Value.Replace("$ynotedir", Application.StartupPath);
        dic.Add(command.Key, command.Value);
    }
    return dic;
}

It uses YnoteCommand class to parse the string because it is also of the format {key}:{value}

Installing a Package

Ynote has built in support for installing packages by using the Package Manager.

Tools->Package Manager will give you a list of available packages. It's a one-click download and install.

You can also install packages from file. Use Install From File to Install a Package from File

Creating a package

You can create a package using the Package Manager.

GoTo Tools->Package Manager Select the Installed Packages Tab and Click Create Package.

Select an output file and add the files you want to and its output destination:

  • $ynotedata - %appdata%\Ynote Classic or {install dir}\Packages in Portable Version
  • $ynotedir - {install dir}\ (same in portable and installable versions, used for copying required assemblies. If you use this, you should install the package as administrator because the user may have installed ynote in the Program Files Directory)

Submitting a Package

You can submit your package by creating a pull request at the ynotepackages repository. See the README.md in the repo for information.

TODO

Ynote has to improve day by day, version by version. Some things I will likely add in the next version (2.9) are listed below:

  • Improve Snippets - Like Textmate's
  • Better Performance and Startup time
  • Switch to IronPython for scripting (Perhaps) and improve API
  • Improved Multiple Caret and Selections support
  • Themable DockPanel
  • Better Syntax Highlighting Interface
  • Improved Project TreeView GUI
  • Improved Settings Framework
  • Improved Commander

External Resources

History

  • Initial release
  • Updated Article ( 2.8.5 Beta )

License

This article, along with any associated source code and files, is licensed under The GNU General Public License (GPLv3)