<commit_before>/*
Copyright (c) 2013 Ant Micro <www.antmicro.com>

Authors:
* <NAME> (<EMAIL>)

Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using System.Linq;
using System.IO;
using AntShell.Terminal;
using AntShell.Commands;
using AntShell.Commands.BuiltIn;
using AntShell.Helpers;

namespace AntShell
{
	public class Shell : ICommandHandler
	{
        public event Action Quitted;

		private readonly TerminalEmulator term;
		private readonly CommandHistory history;
		private readonly CommandLine line;

        public List<ICommand> Commands { get; private set; }

		public string StartupCommand { get; set; }
		public CommandInteraction Writer { get; private set; }

		private readonly ICommandHandler externalHandler;

		private readonly ShellSettings settings;

        public Shell(Stream s, ShellSettings settings) : this(s, s, settings) { }

		public Shell(Stream input, Stream output, ShellSettings settings)
		{
			term = new TerminalEmulator(input, output, settings.ForceVirtualCursor);
			history = new CommandHistory();
            Commands = new List<ICommand>();

			line = new CommandLine(term, history, this);
			line.NormalPrompt = settings.NormalPrompt;
			line.SearchPrompt = settings.SearchPrompt ?? new SearchPrompt("search `{0}`> ", ConsoleColor.Yellow);

			Writer = new CommandInteraction(term, line);

			this.settings = settings;

			PrepareCommands();
		}

		public Shell(Stream s, ICommandHandler handler, ShellSettings settings) : this(s, s, handler, settings) { }

        public Shell(Stream input, Stream output, ICommandHandler handler, ShellSettings settings) : this(input, output, settings)
        {
            externalHandler = handler;
            externalHandler.GetInternalCommands = () => Commands.Cast<ICommandDescription>();
        }

		public void Start(bool stopOnError = false)
		{
			term.Start(settings.ClearScreen);

			if (settings.Banner != null)
			{
				term.Write(settings.Banner, false);
				term.NewLine();
				term.NewLine();
			}
			if (StartupCommand != null)
			{
				term.Write(string.Format("Executing startup command: {0}", StartupCommand), false);
				term.NewLine();
				HandleCommand(StartupCommand, null);
				term.NewLine();
			}

			line.Start();

			term.Run(stopOnError);

            var q = Quitted;
            if (q != null)
            {
                q();
            }
		}

		public void Stop()
		{
			term.Stop();
		}

		public void Reset()
		{
			term.ClearScreen();
			line.CurrentPrompt.Write(term);
		}

		private void PrepareCommands()
		{
			RegisterCommand(new CommandFromHistoryCommand(history));
			RegisterCommand(new HistoryCommand(history));
			RegisterCommand(new SaveCommand(history));

			if (settings.UseBuiltinQuit)
			{
				RegisterCommand(new QuitCommand());
			}

			if (settings.UseBuiltinHelp)
			{
                RegisterCommand(new HelpCommand(Commands));
			}
		}

		public void RegisterCommand(ICommand cmd)
		{
            if (Commands.Any(x => x.Name == cmd.Name))
			{
				throw new ArgumentException("Command name is already registered");
			}

            if (Commands.Any(x => x.AlternativeNames != null && x.AlternativeNames.Contains(cmd.Name)))
			{
                throw new ArgumentException("Command alternative name is already registered");
			}

            Commands.Add(cmd);
		}

		string HandleOnHistorySearch(bool reset, string arg)
		{
			if (reset)
			{
				history.Reset();
			}

			return history.ReverseSearch(arg);
		}

		public string[] SuggestionNeeded(string arg)
		{
            var result = Commands.Where(x => x.Name.StartsWith(arg)).Select(x => x.Name).ToList();
			if (externalHandler != null)
			{
				result.AddRange(externalHandler.SuggestionNeeded(arg));
			}
			return result.ToArray();
		}

		public string BestSuggestionNeeded(string str)
		{
            var result = Commands.Where(x => x.Name.StartsWith(str)).Select(x => x.Name).ToList();
			if (externalHandler != null)
			{
				var bestsug = externalHandler.BestSuggestionNeeded(str);
				if (bestsug != null)
				{
					result.Add(bestsug);
				}
			}
			return Helper.CommonPrefix(result) ?? str;
		}

		public ICommandInteraction HandleCommand(string cmd, ICommandInteraction ic)
		{
			if (cmd != null)
			{
				history.Add(cmd);
			}

			var param = Regex.Matches(cmd, string.Format(@"(?<match>[{0}]+)|\""(?<match>[{0}]*)""", @"\w\.\-\?\!"))
					.Cast<Match>()
					.Select(m => m.Groups["match"].Value)
					.ToArray();

            var command = param.Length > 0 ? Commands.SingleOrDefault(x => 
                (x.Name == param[0]) || x.AlternativeNames.Contains(param[0]) ||
			 	((x is IOperator) ? (param[0].Length > 0 && ((IOperator)x).Operator == param[0][0]) : false)
			) : null;

			if (command == null)
			{
				if (externalHandler != null)
				{
					return externalHandler.HandleCommand(cmd, Writer);
				}

				Writer.WriteError(string.Format("Command {0} not found", param.Length > 0 ? param[0] : cmd));
			}
			else
			{
				if (command is IOperator)
				{
					var list = new List<string> { param[0][0].ToString(), param[0].Substring(1) };
					list.AddRange(param.Skip(1));<commit_msg>Fix for bug with eating tilda and slash characters in paths.<commit_after>/*
Copyright (c) 2013 Ant Micro <www.antmicro.com>

Authors:
* <NAME> (<EMAIL>)

Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using System.Linq;
using System.IO;
using AntShell.Terminal;
using AntShell.Commands;
using AntShell.Commands.BuiltIn;
using AntShell.Helpers;

namespace AntShell
{
	public class Shell : ICommandHandler
	{
        public event Action Quitted;

		private readonly TerminalEmulator term;
		private readonly CommandHistory history;
		private readonly CommandLine line;

        public List<ICommand> Commands { get; private set; }

		public string StartupCommand { get; set; }
		public CommandInteraction Writer { get; private set; }

		private readonly ICommandHandler externalHandler;

		private readonly ShellSettings settings;

        public Shell(Stream s, ShellSettings settings) : this(s, s, settings) { }

		public Shell(Stream input, Stream output, ShellSettings settings)
		{
			term = new TerminalEmulator(input, output, settings.ForceVirtualCursor);
			history = new CommandHistory();
            Commands = new List<ICommand>();

			line = new CommandLine(term, history, this);
			line.NormalPrompt = settings.NormalPrompt;
			line.SearchPrompt = settings.SearchPrompt ?? new SearchPrompt("search `{0}`> ", ConsoleColor.Yellow);

			Writer = new CommandInteraction(term, line);

			this.settings = settings;

			PrepareCommands();
		}

		public Shell(Stream s, ICommandHandler handler, ShellSettings settings) : this(s, s, handler, settings) { }

        public Shell(Stream input, Stream output, ICommandHandler handler, ShellSettings settings) : this(input, output, settings)
        {
            externalHandler = handler;
            externalHandler.GetInternalCommands = () => Commands.Cast<ICommandDescription>();
        }

		public void Start(bool stopOnError = false)
		{
			term.Start(settings.ClearScreen);

			if (settings.Banner != null)
			{
				term.Write(settings.Banner, false);
				term.NewLine();
				term.NewLine();
			}
			if (StartupCommand != null)
			{
				term.Write(string.Format("Executing startup command: {0}", StartupCommand), false);
				term.NewLine();
				HandleCommand(StartupCommand, null);
				term.NewLine();
			}

			line.Start();

			term.Run(stopOnError);

            var q = Quitted;
            if (q != null)
            {
                q();
            }
		}

		public void Stop()
		{
			term.Stop();
		}

		public void Reset()
		{
			term.ClearScreen();
			line.CurrentPrompt.Write(term);
		}

		private void PrepareCommands()
		{
			RegisterCommand(new CommandFromHistoryCommand(history));
			RegisterCommand(new HistoryCommand(history));
			RegisterCommand(new SaveCommand(history));

			if (settings.UseBuiltinQuit)
			{
				RegisterCommand(new QuitCommand());
			}

			if (settings.UseBuiltinHelp)
			{
                RegisterCommand(new HelpCommand(Commands));
			}
		}

		public void RegisterCommand(ICommand cmd)
		{
            if (Commands.Any(x => x.Name == cmd.Name))
			{
				throw new ArgumentException("Command name is already registered");
			}

            if (Commands.Any(x => x.AlternativeNames != null && x.AlternativeNames.Contains(cmd.Name)))
			{
                throw new ArgumentException("Command alternative name is already registered");
			}

            Commands.Add(cmd);
		}

		string HandleOnHistorySearch(bool reset, string arg)
		{
			if (reset)
			{
				history.Reset();
			}

			return history.ReverseSearch(arg);
		}

		public string[] SuggestionNeeded(string arg)
		{
            var result = Commands.Where(x => x.Name.StartsWith(arg)).Select(x => x.Name).ToList();
			if (externalHandler != null)
			{
				result.AddRange(externalHandler.SuggestionNeeded(arg));
			}
			return result.ToArray();
		}

		public string BestSuggestionNeeded(string str)
		{
            var result = Commands.Where(x => x.Name.StartsWith(str)).Select(x => x.Name).ToList();
			if (externalHandler != null)
			{
				var bestsug = externalHandler.BestSuggestionNeeded(str);
				if (bestsug != null)
				{
					result.Add(bestsug);
				}
			}
			return Helper.CommonPrefix(result) ?? str;
		}

		public ICommandInteraction HandleCommand(string cmd, ICommandInteraction ic)
		{
			if (cmd != null)
			{
				history.Add(cmd);
			}

            var param = Regex.Matches(cmd, string.Format(@"(?<match>[{0}]+)|\""(?<match>[{0}]*)""", @"\w\.\-\?\!\~\/"))
					.Cast<Match>()
					.Select(m => m.Groups["match"].Value)
					.ToArray();

            var command = param.Length > 0 ? Commands.SingleOrDefault(x => 
                (x.Name == param[0]) || x.AlternativeNames.Contains(param[0]) ||
			 	((x is IOperator) ? (param[0].Length > 0 && ((IOperator)x).Operator == param[0][0]) : false)
			) : null;

			if (command == null)
			{
				if (externalHandler != null)
				{
					return externalHandler.HandleCommand(cmd, Writer);
				}

				Writer.WriteError(string.Format("Command {0} not found", param.Length > 0 ? param[0] : cmd));
			}
			else
			{
				if (command is IOperator)
				{
					var list = new List<string> { param[0][0].ToString(), param[0].Substring(1) };
					list.AddRange(param.Skip(1));
{'fraction_non_alphanumeric': 0.11482137109752172, 'fraction_numerical': 0.003701319600901191, 'mean_word_length': 3.324634655532359, 'pattern_counts': {'":': 0, '<': 23, '<?xml version=': 0, '>': 49, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, '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': '460590', 'n_tokens_mistral': 4179, 'n_tokens_neox': 3564, 'n_words': 1033}