/// <summary> /// display a bar of text that wait a text input /// </summary> /// <param name="text"></param> /// <param name="inputMap"></param> /// <returns></returns> public static object InputBar(CommandEvaluationContext context, string text, List <InputMap> inputMaps) { object r = null; context.Out.Echo($"{context.ShellEnv.Colors.InteractionBar}{text}{ANSI.RSTXTA}"); bool end = false; string input = ""; while (!end) { var c = sc.ReadKey(true); if (!Char.IsControl(c.KeyChar)) { input += c.KeyChar; } bool partialMatch = false; foreach (var inputMap in inputMaps) { var match = inputMap.Match(input, c); if (match == InputMap.ExactMatch) { r = inputMap.Code; end = true; break; } partialMatch |= match == InputMap.PartialMatch; } if (!partialMatch) { input = ""; } System.Diagnostics.Debug.WriteLine($"{input}"); } return(r); }
UnregisterModuleCommands( CommandEvaluationContext context, string modulePackageId) { modulePackageId = modulePackageId?.ToLower(); var moduleSpecification = _modules.Values.Where(x => x.Key.ToLower() == modulePackageId).FirstOrDefault(); if (moduleSpecification != null) { foreach (var com in AllCommands) { if (com.MethodInfo.DeclaringType.Assembly == moduleSpecification.Assembly) { UnregisterCommand(com); } } return(moduleSpecification); } else { context.Errorln($"commands module '{modulePackageId}' not registered"); return(ModuleSpecification.ModuleSpecificationNotDefined); } }
static void AddObjectToTable( CommandEvaluationContext context, Table table, object obj, TableFormattingOptions options, int level = 0 ) { var tab = "".PadLeft((level * 4), ' '); var prfx = context.ShellEnv.Colors.HalfDarkLabel; foreach (var(name, value, inf) in obj.GetMemberValues()) { var attrs = GetMemberConstraintsText(context, inf); if (value == null) { table.Rows.Add(tab + prfx + name + attrs + Rdc, inf.GetMemberValueType().UnmangledName(), DumpAsText(context, null)); } else { table.Rows.Add(tab + prfx + name + attrs + Rdc, inf.GetMemberValueType().UnmangledName(), value); } } }
public CommandResult <HttpContentBody> Get( CommandEvaluationContext context, [Parameter("query string")] string queryString ) { string @return = null; if (string.IsNullOrWhiteSpace(queryString)) { context.Errorln("uri must not be empty"); return(new CommandResult <HttpContentBody>(HttpContentBody.EmptyHttpContentBody)); } if (!queryString.ToLower().StartsWith("http://") && !queryString.ToLower().StartsWith("https://")) { queryString = "http://" + queryString; } using (var httpClient = new HttpClient()) { using var request = new HttpRequestMessage(new HttpMethod("GET"), queryString); var tsk = httpClient.SendAsync(request); var result = tsk.Result; if (result.IsSuccessStatusCode) { @return = result.Content.ReadAsStringAsync().Result; context.Out.Echo(@return, true, true); } else { context.Errorln($"can't get response content: {result.ReasonPhrase}"); } } return(new CommandResult <HttpContentBody>(new HttpContentBody(@return))); }
public CommandResult <(List <FileSystemPath> items, FindCounts counts)> Dir( CommandEvaluationContext context, [Parameter("path where to list files and folders. if not specified is equal to the current directory. use wildcards * and ? to filter files and folders names", true)] WildcardFilePath path, [Option("na", "do not print file system attributes")] bool noattributes, [Option("r", "also list files and folders in sub directories. force display files full path")] bool recurse, [Option("w", "displays file names on several columns so output fills console width (only if not recurse mode). disable print of attributes")] bool wide ) { var r = new List <FileSystemPath>(); path ??= new WildcardFilePath(Environment.CurrentDirectory); if (path.CheckExists()) { var counts = new FindCounts(); var items = FindItems(context, path.FullName, path.WildCardFileName ?? "*", !recurse, true, false, !noattributes, !recurse, null, false, counts, false, false); var f = DefaultForegroundCmd; long totFileSize = 0; var cancellationTokenSource = new CancellationTokenSource(); if (wide) { noattributes = true; } void postCmd(object o, EventArgs e) { sc.CancelKeyPress -= cancelCmd; context.Out.Echoln($"{Tab}{ColorSettings.Numeric}{Plur("file", counts.FilesCount, f),-30}{HumanFormatOfSize(totFileSize, 2," ", ColorSettings.Numeric.ToString(), f)}"); context.Out.Echoln($"{Tab}{ColorSettings.Numeric}{Plur("folder", counts.FoldersCount, f),-30}{Drives.GetDriveInfo(path.FileSystemInfo.FullName,false, ColorSettings.Numeric.ToString(), f," ",2)}"); } void cancelCmd(object o, ConsoleCancelEventArgs e) { e.Cancel = true; cancellationTokenSource.Cancel(); } int printResult() { var i = 0; int maxitlength = 0; counts.FilesCount = counts.FoldersCount = 0; foreach (var item in items) { if (item.IsFile) { totFileSize += ((FileInfo)item.FileSystemInfo).Length; counts.FilesCount++; } else { counts.FoldersCount++; } maxitlength = Math.Max(item.Name.Length, maxitlength); } maxitlength += 4; var(id, left, top, right, bottom) = DotNetConsole.ActualWorkArea(); var nbcols = Math.Floor((double)(right - left + 1) / (double)maxitlength); int nocol = 0; foreach (var item in items) { if (cancellationTokenSource.IsCancellationRequested) { return(i); } item.Print(!noattributes, !recurse, "", (!wide || recurse || nocol == nbcols - 1) ? Br : "", (wide && !recurse) ? maxitlength : -1); i++; nocol++; if (nocol == nbcols) { nocol = 0; } } if (!recurse && wide && nocol < nbcols && nocol > 0) { context.Out.Echoln(); } return(i); } sc.CancelKeyPress += cancelCmd; var task = Task.Run <int>(() => printResult(), cancellationTokenSource.Token); try { task.Wait(cancellationTokenSource.Token); } catch (OperationCanceledException) { var res = task.Result; } postCmd(null, null); return(new CommandResult <(List <FileSystemPath>, FindCounts)>((items, counts))); } return(new CommandResult <(List <FileSystemPath>, FindCounts)>((r, new FindCounts()), ReturnCode.Error)); }
public CommandResult <(List <FileSystemPath> items, FindCounts counts)> Rm( CommandEvaluationContext context, [Parameter("file or folder path")] WildcardFilePath path, [Option("r", "also remove files and folders in sub directories")] bool recurse, [Option("i", "prompt before any removal")] bool interactive, [Option("v", "explain what is being done")] bool verbose, [Option("d", "remove empty directories")] bool rmEmptyDirs, [Option("na", "do not print file system attributes when verbose")] bool noattributes, [Option("s", "don't remove any file/or folder, just simulate the operation (enable verbose)")] bool simulate ) { var r = new List <FileSystemPath>(); var counts = new FindCounts(); if (path.CheckExists()) { var items = FindItems(context, path.FullName, path.WildCardFileName ?? "*", !recurse, true, false, !noattributes, !recurse, null, false, counts, false, false); var cancellationTokenSource = new CancellationTokenSource(); verbose |= simulate; void cancelCmd(object o, ConsoleCancelEventArgs e) { e.Cancel = true; cancellationTokenSource.Cancel(); }; void postCmd(object o, EventArgs e) { sc.CancelKeyPress -= cancelCmd; } List <FileSystemPath> processRemove() { var r = new List <FileSystemPath>(); foreach (var item in items) { if (cancellationTokenSource.IsCancellationRequested) { return(r); } bool deleted = false; if (item.IsFile) { if (item.FileSystemInfo.Exists && !r.Contains(item)) { if (interactive) { if (Confirm("rm: remove file " + item.GetPrintableName(recurse)) && !simulate) { if (!simulate) { item.FileSystemInfo.Delete(); } deleted = true; } } else { if (!simulate) { item.FileSystemInfo.Delete(); } deleted = true; } } } else { var dp = (DirectoryPath)item; if ((rmEmptyDirs && dp.IsEmpty) || recurse) { if (dp.DirectoryInfo.Exists && !r.Contains(dp)) { if (interactive) { r.Merge(RecurseInteractiveDeleteDir(context, dp, simulate, noattributes, verbose, cancellationTokenSource)); } else { if (!simulate) { dp.DirectoryInfo.Delete(recurse); } deleted = true; } } } } if (deleted) { if (verbose) { item.Print(!noattributes, !recurse, "", Br, -1, "removed "); } r.Add(item); } } return(r); }; sc.CancelKeyPress += cancelCmd; var task = Task.Run(() => processRemove(), cancellationTokenSource.Token); try { task.Wait(cancellationTokenSource.Token); } catch (OperationCanceledException) { r = task.Result; } postCmd(null, null); return(new CommandResult <(List <FileSystemPath>, FindCounts)>((r, counts), ReturnCode.OK)); } else { return(new CommandResult <(List <FileSystemPath>, FindCounts)>((r, counts), ReturnCode.Error)); } }
public CommandResult <List <FilePath> > CheckIntegrity( CommandEvaluationContext context, [Parameter("path of a file to be checked or path from where find files to to be checked")] FileSystemPath fileOrDir, [Option("p", "pattern", "select names that matches the pattern", true, true)] string pattern, [Option("i", "non-sensitive", "if set and p is set, perform a non case sensisitive search")] bool ignoreCase, [Option("a", "attr", "print file system attributes")] bool printAttr, [Option("t", "top", "search in top directory only")] bool top, [Option("q", "quiet", "quiet mode: do not print error message below corrupted file name")] bool quiet, [Option("r", "ratio", "acceptable ratio of non printable characters", true, true)] double ratio = 30, [Option("s", "min-size", "minimum size of analysed part of the text", true, true)] int minSeqLength = 1024 ) { var r = new List <FilePath>(); if (fileOrDir.CheckExists(context)) { if (fileOrDir.IsFile) { var(isValid, filePath) = CheckIntegrity(context, new FilePath(fileOrDir.FullName), ratio, printAttr, minSeqLength, quiet); if (!isValid) { r.Add(filePath); } return(new CommandResult <List <FilePath> >(r)); } else { var sp = string.IsNullOrWhiteSpace(pattern) ? "*" : pattern; var counts = new FindCounts(); var items = FindItems(context, fileOrDir.FullName, sp, top, false, false, printAttr, false, null, false, counts, false, false, ignoreCase); var f = context.ShellEnv.Colors.Default.ToString(); var elapsed = DateTime.Now - counts.BeginDateTime; context.Out.Echoln($"found {context.ShellEnv.Colors.Numeric}{Plur("file", counts.FilesCount, f)} and {context.ShellEnv.Colors.Numeric}{Plur("folder", counts.FoldersCount, f)}. scanned {context.ShellEnv.Colors.Numeric}{Plur("file", counts.ScannedFilesCount, f)} in {context.ShellEnv.Colors.Numeric}{Plur("folder", counts.ScannedFoldersCount, f)} during {TimeSpanDescription(elapsed, context.ShellEnv.Colors.Numeric.ToString(), f)}"); if (items.Count > 0) { context.Out.Echoln($"analyzing files ({counts.FilesCount})..."); int corruptedFilesCount = 0; foreach (var item in items) { if (context.CommandLineProcessor.CancellationTokenSource.Token.IsCancellationRequested) { break; } if (item.IsFile) { if (!CheckIntegrity(context, (FilePath)item, ratio, printAttr, minSeqLength, quiet).isValid) { corruptedFilesCount++; r.Add((FilePath)item); } } } if (corruptedFilesCount > 0) { context.Out.Echoln(); } var crprt = (double)corruptedFilesCount / (double)counts.FilesCount * 100d; context.Out.Echoln($"found {context.ShellEnv.Colors.Numeric}{Plur("corrupted file", corruptedFilesCount, f)} in {context.ShellEnv.Colors.Numeric}{Plur("file", counts.FilesCount, f)} corruption ratio={Cyan}{crprt}%"); return(new CommandResult <List <FilePath> >(r)); } else { return(new CommandResult <List <FilePath> >(r)); } } } else { return(new CommandResult <List <FilePath> >(new List <FilePath> { new FilePath(fileOrDir.FullName) }, ReturnCode.Error)); } }
public CommandVoidResult AnsiColorTest( CommandEvaluationContext context ) { // 3 bits colors (standard) var colw = 8; var totw = colw * 8 + 3 + 10; var hsep = "".PadLeft(totw, '-'); var esc = (char)27; string r; int x2 = 0; context.Out.Echoln("3 bits (8 color mode)"); context.Out.Echoln(); context.Out.Echoln("Background | Foreground colors"); context.Out.Echoln(hsep); for (int j = 0; j <= 7; j++) { var str1 = $" ESC[4{j}m | {esc}[4{j}m"; var str2 = $" ESC[10{j}m | {esc}[10{j}m"; for (int i = 0; i <= 7; i++) { str1 += Set4BitsColors(i, j | 0b1000) + $" [9{i}m "; str2 += Set4BitsColors(i | 0b1000, j) + $" [3{i}m "; } context.Out.Echoln(str1 + context.ShellEnv.Colors.Default); context.Out.Echoln(str2 + context.ShellEnv.Colors.Default); context.Out.Echoln(hsep); } context.Out.Echoln(context.ShellEnv.Colors.Default + ""); // 8 bits colors context.Out.Echoln("8 bits (256 color mode)"); context.Out.Echoln(); context.Out.Echoln("216 colors: 16 + 36 × r + 6 × g + b (0 <= r, g, b <= 5)(br)"); int n = 16; for (int y = 0; y < 6; y++) { r = ""; for (int x = 16; x <= 51; x++) { if (x >= 34) { r += Black; } else { r += White; } r += $"{esc}[48;5;{n}m" + ((n + "").PadLeft(4, ' ')); n++; x2++; if (x2 >= 6) { r += Br; x2 = 0; } } context.Out.Echo(r); } context.Out.Echoln(context.ShellEnv.Colors.Default + ""); context.Out.Echoln("grayscale colors (24 colors) : 232 + l (0 <= l <= 24)(br)"); r = White; x2 = 0; for (int x = 232; x <= 255; x++) { if (x >= 244) { r += Black; } r += $"{esc}[48;5;{x}m" + ((x + "").PadLeft(4, ' ')); x2++; if (x2 >= 6) { r += context.Out.LNBRK; x2 = 0; } } context.Out.Echo(r); context.Out.Echoln(context.ShellEnv.Colors.Default + ""); context.Out.Echoln("24 bits (16777216 colors): 0 <= r,g,b <= 255 (br) "); string cl(int r, int v, int b) => esc + "[48;2;" + r + ";" + v + ";" + b + "m "; var stp = 4; r = ""; int cr, cb = 0, cv = 0; for (cr = 0; cr < 255; cr += stp) { r += cl(cr, cv, cb); } context.Out.Echoln(r); r = ""; cr = 0; for (cv = 0; cv < 255; cv += stp) { r += cl(cr, cv, cb); } context.Out.Echoln(r); cv = 0; r = ""; for (cb = 0; cb < 255; cb += stp) { r += cl(cr, cv, cb); } context.Out.Echoln(r); r = ""; for (cb = 0; cb < 255; cb += stp) { r += cl(cb, cb, 0); } context.Out.Echoln(r); r = ""; for (cb = 0; cb < 255; cb += stp) { r += cl(cb, 0, cb); } context.Out.Echoln(r); r = ""; for (cb = 0; cb < 255; cb += stp) { r += cl(0, cb, cb); } context.Out.Echoln(r); r = ""; for (cb = 0; cb < 255; cb += stp) { r += cl(cb, cb, cb); } context.Out.Echoln(r); return(new CommandVoidResult()); }
string Input(CommandEvaluationContext context, string prompt) { context.Out.Echo(prompt); return(context.In.ReadLine()); }
/// <summary> /// search items in file system /// </summary> /// <param name="context"></param> /// <param name="path"></param> /// <param name="pattern"></param> /// <param name="top"></param> /// <param name="all"></param> /// <param name="dirs"></param> /// <param name="attributes"></param> /// <param name="shortPathes"></param> /// <param name="contains"></param> /// <param name="checkPatternOnFullName"></param> /// <param name="counts"></param> /// <param name="print"></param> /// <param name="alwaysSelectDirs"></param> /// <param name="ignoreCase"></param> /// <param name="printMatches"></param> /// <returns></returns> public static List <FileSystemPath> FindItems( CommandEvaluationContext context, string path, string pattern, bool top, bool all, bool dirs, bool attributes, bool shortPathes, string contains, bool checkPatternOnFullName, FindCounts counts, bool print, bool alwaysSelectDirs = false, bool ignoreCase = false, bool printMatches = false) { bool isFile = File.Exists(path); var dinf = isFile ? null : new DirectoryInfo(path); List <FileSystemPath> items = new List <FileSystemPath>(); bool hasPattern = !string.IsNullOrWhiteSpace(pattern); bool hasContains = !string.IsNullOrWhiteSpace(contains); if (context.CommandLineProcessor.IsCancellationRequested) { return(items); } try { if (!isFile) { counts.ScannedFoldersCount++; } var scan = isFile ? new FileSystemInfo[] { new FileInfo(path) } : dinf.GetFileSystemInfos(); foreach (var fsinf in scan) { var sitem = FileSystemPath.Get(fsinf); if (sitem.IsDirectory) { if ((dirs || all) && (alwaysSelectDirs || (!hasPattern || MatchWildcard(pattern, checkPatternOnFullName ? sitem.FileSystemInfo.FullName : sitem.FileSystemInfo.Name, ignoreCase)))) { items.Add(sitem); if (print) { sitem.Echo(new EchoEvaluationContext(context.Out, context, new FileSystemPathFormattingOptions(attributes, shortPathes, "", Br))); } counts.FoldersCount++; } else { sitem = null; } if (!top) { items.AddRange(FindItems(context, fsinf.FullName, pattern, top, all, dirs, attributes, shortPathes, contains, checkPatternOnFullName, counts, print, alwaysSelectDirs, ignoreCase, printMatches)); } } else { counts.ScannedFilesCount++; if (!dirs && (!hasPattern || MatchWildcard(pattern, checkPatternOnFullName ? sitem.FileSystemInfo.FullName : sitem.FileSystemInfo.Name, ignoreCase))) { var matches = new List <string>(); if (hasContains) { try { if (!FilePath.IsBinaryFile(sitem.FileSystemInfo.FullName)) { // skip non text files var(lines, platform, eol) = TextFileReader.ReadAllLines(sitem.FileSystemInfo.FullName); bool match = false; for (int i = 0; i < lines.Length; i++) { if (lines[i].Contains(contains)) { match |= true; if (printMatches) { int j = lines[i].IndexOf(contains); var loc = $"\t{context.ShellEnv.Colors.MarginText} {$"line {i},col {j}".PadRight(24)} "; var txt = lines[i].Replace(contains, context.ShellEnv.Colors.TextExtractSelectionBlock + contains + Rdc + context.ShellEnv.Colors.TextExtract); matches.Add(loc + context.ShellEnv.Colors.TextExtract + txt + Rdc); } } } if (!match) { sitem = null; } } else { sitem = null; } } catch (Exception ex) { context.Errorln($"file read error: {ex.Message} when accessing file: {sitem.PrintableFullName}"); sitem = null; } } if (sitem != null) { counts.FilesCount++; items.Add(sitem); if (print && context.Out.IsModified && matches.Count > 0) { context.Out.Echoln(""); } if (print) { sitem.Echo(new EchoEvaluationContext(context.Out, context, new FileSystemPathFormattingOptions(attributes, shortPathes, "", Br))); } } if (matches.Count > 0) { matches.ForEach(x => context.Out.Echoln(x)); } matches.Clear(); } else { sitem = null; } } if (context.CommandLineProcessor.IsCancellationRequested) { return(items); } } return(items); } catch (UnauthorizedAccessException) { context.Errorln($"unauthorized access to {new DirectoryPath(path).PrintableFullName}"); return(items); } }
public static string QuotedString(CommandEvaluationContext context, string s) => $"{context.ShellEnv.Colors.Quotes}\"{context.ShellEnv.Colors.Default}{s}{context.ShellEnv.Colors.Quotes}\"{context.ShellEnv.Colors.Default}";
public static string DumpNull(CommandEvaluationContext context) => DumpAsText(context, null);
public CommandVoidResult DoomFireAlgo( CommandEvaluationContext context, [Option("w", "width", "width in characters", true, true)] int width = 100, [Option("h", "height", "height in characters", true, true)] int height = 40, [Option("d", "decay-delta", "decay delta", true, true)] int decayDelta = 3, [Option("g", "gray", "gray mode - no colors")] bool gray = false, [Option("s", "slow", "0 max speed - pause time between images in ms", true, true)] int slow = 0, [Option("t", "no-text", "do not add text info above anim")] bool noText = false, [Option(null, "color-palette", "color palette. 36 symbols separated by " + PalettePatternSeparator, true, true)] string firePattern = DefaultFirePattern ) { // remove directives to speed up (TODO: the directives lead to stack overflow in this case) firePattern = firePattern.ToLower(); var firePallete = firePattern.Split(PalettePatternSeparator); var sb = new StringBuilder(width * height * 20); if (!gray) { // add colors var n = firePallete.Length; var stp = 256 / n; int r = 0; int g = 0; int b = 0; for (int i = 0; i < firePallete.Length; i++) { firePallete[i] = ANSI.SGR_SetForegroundColor24bits(r, g, b) + firePallete[i]; r += stp; if (r > 100) { g += stp; } } } var o = context.Out; o.Echo("pixelPalete.Length=" + firePallete.Length); var pixels = width * height; var pixelsArray = new int[pixels]; var random = new Random(); void createPixelsStructure() { for (var i = 0; i < pixels; i++) { pixelsArray[i] = 0; } }; void calculatePropagation() { for (var column = 0; column < width; column++) { for (var row = 0; row < height; row++) { var index = column + (width * row); updatePixelIntensity(index); } } }; void updatePixelIntensity(int index) { var belowIndex = index + width; if (belowIndex < width * height) { var decay = (int)Math.Floor(random.NextDouble() * decayDelta); var belowIntensity = pixelsArray[belowIndex]; var newIntensity = belowIntensity - decay; if (index - decay > 0) { pixelsArray[index - decay] = newIntensity > 0 ? newIntensity : 0; } } }; void createSource() { for (var column = 0; column < width; column++) { var overflowPixel = width * height; var index = (overflowPixel - width) + column; pixelsArray[index] = firePallete.Length - 1; } }; void render() { sb.Clear(); sb.Append(ANSI.CUP()); for (var row = 0; row < height; row++) { for (var column = 0; column < width; column++) { var index = column + (width * row); var intensity = pixelsArray[index]; sb.Append(firePallete[intensity]); } sb.AppendLine(); } o.ConsolePrint(sb.ToString()); // fast print }; void start() { o.ClearScreen(); try { o.HideCur(); } catch (Exception ex) { o.Errorln(ex.Message); } createPixelsStructure(); createSource(); } start(); var end = false; while (!end) { var sw0 = Stopwatch.StartNew(); calculatePropagation(); sw0.Stop(); var sw1 = Stopwatch.StartNew(); render(); sw1.Stop(); if (!noText) { o.Echoln($"(rdc)Doom fire algo - {Math.Round(1d / (sw0.ElapsedMilliseconds+sw1.ElapsedMilliseconds) * 1000,2)} fps"); } //end = context.CommandLineProcessor.CancellationTokenSource.IsCancellationRequested; end = context.CommandLineProcessor.IsCancellationRequested; if (slow > 0) { Thread.Sleep(slow); } } o.ShowCur(); return(CommandVoidResult.Instance); }
public int RegisterCommandClass( CommandEvaluationContext context, Type type, bool registerAsModule ) { if (type.GetInterface(typeof(ICommandsDeclaringType).FullName) == null) { throw new Exception($"the type '{type.FullName}' must implements interface '{typeof(ICommandsDeclaringType).FullName}' to be registered as a command class"); } var dtNamespaceAttr = type.GetCustomAttribute <CommandsNamespaceAttribute>(); var dtNamespace = (dtNamespaceAttr == null) ? "" : CheckAndNormalizeCommandNamespace(dtNamespaceAttr.Segments); var comsCount = 0; object instance = Activator.CreateInstance(type, new object[] { }); var methods = type.GetMethods(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly); if (registerAsModule && _modules.ContainsKey(type.FullName)) { context.Errorln($"a module with same name than the commands declaring type '{type.FullName}' is already registered"); return(0); } foreach (var method in methods) { var cmd = method.GetCustomAttribute <CommandAttribute>(); if (cmd != null) { if (!method.ReturnType.HasInterface(typeof(ICommandResult))) { context.Errorln($"class={type.FullName} method={method.Name} wrong return type. should be of type '{typeof(ICommandResult).FullName}', but is of type: {method.ReturnType.FullName}"); } else { // ⏺ build the command specification from the method meta-data var cmdNamespaceAttr = method.GetCustomAttribute <CommandNamespaceAttribute>(); var cmdNamespace = cmdNamespaceAttr == null ? dtNamespace : CheckAndNormalizeCommandNamespace(cmdNamespaceAttr.Segments); var cmdAliasesAttrLst = method.GetCustomAttributes <CommandAliasAttribute>(); var cmdAliases = cmdAliasesAttrLst?.Select(x => (x.AliasName, x.AliasText)).ToList(); if (cmdAliases.Count == 0) { cmdAliases = null; // convention } #region init from method parameters attributes var paramspecs = new List <CommandParameterSpecification>(); bool syntaxError = false; var pindex = 0; foreach (var parameter in method.GetParameters()) { if (pindex == 0) { // manadatory: param 0 is CommandEvaluationContext if (parameter.ParameterType != typeof(CommandEvaluationContext)) { context.Errorln($"class={type.FullName} method={method.Name} parameter 0 ('{parameter.Name}') should be of type '{typeof(CommandEvaluationContext).FullName}', but is of type: {parameter.ParameterType.FullName}"); syntaxError = true; break; } } else { CommandParameterSpecification pspec = null; object defval = null; if (!parameter.HasDefaultValue && parameter.ParameterType.IsValueType) { defval = Activator.CreateInstance(parameter.ParameterType); } // param var paramAttr = parameter.GetCustomAttribute <ParameterAttribute>(); if (paramAttr != null) { // TODO: validate command specification (eg. indexs validity) pspec = new CommandParameterSpecification( parameter.Name, paramAttr.Description, paramAttr.IsOptional, paramAttr.Index, null, null, true, parameter.HasDefaultValue, paramAttr.HasDefaultValue ? paramAttr.DefaultValue : ((parameter.HasDefaultValue) ? parameter.DefaultValue : defval), parameter); } // option var optAttr = parameter.GetCustomAttribute <OptionAttribute>(); if (optAttr != null) { var reqParamAttr = parameter.GetCustomAttribute <OptionRequireParameterAttribute>(); try { pspec = new CommandParameterSpecification( parameter.Name, optAttr.Description, optAttr.IsOptional, -1, optAttr.OptionName /*?? parameter.Name*/, optAttr.OptionLongName, optAttr.HasValue, parameter.HasDefaultValue, optAttr.HasDefaultValue ? optAttr.DefaultValue : ((parameter.HasDefaultValue) ? parameter.DefaultValue : defval), parameter, reqParamAttr?.RequiredParameterName); } catch (Exception ex) { context.Errorln(ex.Message); } } if (pspec == null) { syntaxError = true; context.Errorln($"invalid parameter: class={type.FullName} method={method.Name} name={parameter.Name}"); } else { paramspecs.Add(pspec); } } pindex++; } #endregion if (!syntaxError) { var cmdNameAttr = method.GetCustomAttribute <CommandNameAttribute>(); var cmdName = CheckAndNormalizeCommandName( (cmdNameAttr != null && cmdNameAttr.Name != null) ? cmdNameAttr.Name : (cmd.Name ?? method.Name)); bool registered = true; CommandSpecification cmdspec = null; try { cmdspec = new CommandSpecification( cmdNamespace, cmdName, cmd.Description, cmd.LongDescription, cmd.Documentation, method, instance, cmdAliases, paramspecs); } catch (Exception ex) { context.Errorln($"error in command '{cmdName}' specification: {ex.Message}"); } if (cmdspec != null) { if (_commands.TryGetValue(cmdspec.Name, out var cmdlst)) { if (cmdlst.Select(x => x.MethodInfo.DeclaringType == type).Any()) { context.Errorln($"command already registered: '{cmdspec.Name}' in type '{cmdspec.DeclaringTypeFullName}'"); registered = false; } else { cmdlst.Add(cmdspec); } } else { _commands.Add(cmdspec.Name, new List <CommandSpecification> { cmdspec }); } if (registered) { _syntaxAnalyzer.Add(cmdspec); comsCount++; // register command Aliases if (cmdspec.Aliases != null) { foreach (var alias in cmdspec.Aliases) { context.CommandLineProcessor.CommandsAlias.AddOrReplaceAlias( context, alias.name, alias.text ); } } } } } } } } if (registerAsModule) { if (comsCount == 0) { context.Errorln($"no commands found in type '{type.FullName}'"); } else { var descAttr = type.GetCustomAttribute <CommandsAttribute>(); var description = descAttr != null ? descAttr.Description : ""; _modules.Add( type.FullName, // key not from assembly but from type new ModuleSpecification( type.FullName, ModuleUtil.DeclaringTypeShortName(type), description, type.Assembly, new ModuleInfo( 1, comsCount ), type )); } } return(comsCount); }
public int RegisterCommandClass(CommandEvaluationContext context, Type type) => RegisterCommandClass(context, type, true);
public CommandVoidResult History( CommandEvaluationContext context, [Option("i", "invoke the command at the entry number in the history list", true, true)] int num, [Option("c", "clear the loaded history list")] bool clear, [Option("w", "write history lines to the history file (content of the file is replaced)")] [OptionRequireParameter("file")] bool writeToFile, [Option("a", "append history lines to the history file")] [OptionRequireParameter("file")] bool appendToFile, [Option("r", "read the history file and append the content to the history list")] [OptionRequireParameter("file")] bool readFromFile, [Option("n", "read the history file and append the content not already in the history list to the history list")] [OptionRequireParameter("file")] bool appendFromFile, [Parameter(1, "file", true)] FilePath file ) { var hist = context.CommandLineProcessor.CmdsHistory.History; var max = hist.Count().ToString().Length; int i = 1; var f = DefaultForegroundCmd; if (num > 0) { if (num < 1 || num > hist.Count) { Errorln($"history entry number out of range (1..{hist.Count})"); return(new CommandVoidResult(ReturnCode.Error)); } var h = hist[num - 1]; context.CommandLineProcessor.CommandLineReader.SendNextInput(h); return(new CommandVoidResult()); } if (clear) { context.CommandLineProcessor.CmdsHistory.ClearHistory(); return(new CommandVoidResult()); } if (appendToFile || readFromFile || appendFromFile || writeToFile) { file ??= context.CommandLineProcessor.CmdsHistory.FilePath; if (file.CheckPathExists()) { if (writeToFile) { File.Delete(context.CommandLineProcessor.CmdsHistory.FilePath.FullName); File.AppendAllLines(file.FullName, hist); } if (appendToFile) { File.AppendAllLines(file.FullName, hist); } if (readFromFile) { var lines = File.ReadAllLines(file.FullName); foreach (var line in lines) { context.CommandLineProcessor.CmdsHistory.HistoryAppend(line); } context.CommandLineProcessor.CmdsHistory.HistorySetIndex(-1, false); } if (appendFromFile) { var lines = File.ReadAllLines(file.FullName); foreach (var line in lines) { if (!context.CommandLineProcessor.CmdsHistory.HistoryContains(line)) { context.CommandLineProcessor.CmdsHistory.HistoryAppend(line); } } context.CommandLineProcessor.CmdsHistory.HistorySetIndex(-1, false); } } return(new CommandVoidResult()); } foreach (var h in hist) { if (context.CommandLineProcessor.CancellationTokenSource.IsCancellationRequested) { break; } var hp = $" {ColorSettings.Numeric}{i.ToString().PadRight(max + 2, ' ')}{f}"; context.Out.Echo(hp); Out.ConsolePrint(h, true); i++; } return(new CommandVoidResult()); }
public CommandVoidResult ShowCursor(CommandEvaluationContext context) { context.Out.ShowCur(); return(CommandVoidResult.Instance); }
static void _Echo( this DataTable table, ConsoleTextWriterWrapper @out, CommandEvaluationContext context, TableFormattingOptions options = null) { options ??= context.ShellEnv.GetValue <TableFormattingOptions>(ShellEnvironmentVar.display_tableFormattingOptions); @out.EnableFillLineFromCursor = false; @out.HideCur(); var colLengths = new int[table.Columns.Count]; foreach (var rw in table.Rows) { var cols = ((DataRow)rw).ItemArray; for (int i = 0; i < cols.Length; i++) { string s, s2; if (table is Table t) { s = @out.GetPrint(t.GetFormatedValue(context, table.Columns[i].ColumnName, cols[i]?.ToString())) ?? ""; colLengths[i] = Math.Max(s.Length, colLengths[i]); s2 = @out.GetPrint(t.GetFormatedHeader(table.Columns[i].ColumnName)) ?? ""; colLengths[i] = Math.Max(s2.Length, colLengths[i]); if (i == cols.Length - 1) { colLengths[i] = s.Length + 2; } } else { s = @out.GetPrint(cols[i]?.ToString()) ?? ""; colLengths[i] = Math.Max(s.Length, colLengths[i]); colLengths[i] = Math.Max(table.Columns[i].ColumnName.Length, colLengths[i]); if (i == cols.Length - 1) { colLengths[i] = 1; } if (i == cols.Length - 1) { colLengths[i] = s.Length + 2; } } } } var colsep = options.NoBorders ? " ".PadLeft(Math.Max(1, options.ColumnRightMargin)) : (context.ShellEnv.Colors.TableBorder + " | " + context.ShellEnv.Colors.Default); var colseplength = options.NoBorders ? 0 : 3; var tablewidth = options.NoBorders ? 0 : 3; for (int i = 0; i < table.Columns.Count; i++) { tablewidth += table.Columns[i].ColumnName.PadRight(colLengths[i], ' ').Length + colseplength; } var line = options.NoBorders ? "" : (context.ShellEnv.Colors.TableBorder + "".PadRight(tablewidth, '-')); if (!options.NoBorders) { @out.Echoln(line); } string fxh(string header) => (table is Table t) ? t.GetFormatedHeader(header) : header; // headers for (int i = 0; i < table.Columns.Count; i++) { if (!options.NoBorders && i == 0) { @out.Echo(colsep); } var col = table.Columns[i]; var colName = (i == table.Columns.Count - 1 && !options.PadLastColumn) ? fxh(col.ColumnName) : fxh(col.ColumnName).PadRight(colLengths[i], ' '); var prfx = (options.NoBorders) ? Uon : ""; var pofx = (options.NoBorders) ? Tdoff : ""; @out.Echo(context.ShellEnv.Colors.TableColumnName + prfx + colName + colsep + pofx); } @out.Echoln(); if (!options.NoBorders) { @out.Echoln(line); } // rows string fhv(string header, string value) => (table is Table t) ? t.GetFormatedValue(context, header, value) : value; foreach (var rw in table.Rows) { if (context.CommandLineProcessor.CancellationTokenSource.IsCancellationRequested) { @out.EnableFillLineFromCursor = true; @out.ShowCur(); @out.Echoln(context.ShellEnv.Colors.Default + ""); return; } var row = (DataRow)rw; var arr = row.ItemArray; for (int i = 0; i < arr.Length; i++) { if (!options.NoBorders && i == 0) { @out.Echo(colsep); } var txt = (arr[i] == null) ? "" : arr[i].ToString(); var fvalue = fhv(table.Columns[i].ColumnName, txt); var o = arr[i]; MethodInfo mi = null; if (((!(o is string)) || table.Columns[i].DataType == typeof(object)) && o != null && (mi = o.GetEchoMethod()) != null) { // value dump via Echo primitive @out.Echo("" + context.ShellEnv.Colors.Default); var p0 = @out.CursorPos; mi.InvokeEcho(o, new EchoEvaluationContext(@out, context, new FormatingOptions(options) { LineBreak = false })); var p1 = @out.CursorPos; if (p1.Y == p0.Y) { var l = p1.X - p0.X; var spc = (i == arr.Length - 1 && !options.PadLastColumn) ? "" : ("".PadRight(Math.Max(0, colLengths[i] - l), ' ')); @out.Echo(spc); } @out.Echo(colsep); } else { // value dump by ToString var l = @out.GetPrint(fvalue).Length; var spc = (i == arr.Length - 1 && !options.PadLastColumn) ? "" : ("".PadRight(Math.Max(0, colLengths[i] - l), ' ')); @out.Echo("" + context.ShellEnv.Colors.Default); @out.Echo(fvalue); @out.Echo(spc + colsep); } } @out.Echoln(); } @out.Echo(line + context.ShellEnv.Colors.Default.ToString()); @out.ShowCur(); @out.EnableFillLineFromCursor = true; }
public ModuleSpecification RegisterModule( CommandEvaluationContext context, Assembly assembly) { ModuleSpecification moduleSpecification; var moduleAttr = assembly.GetCustomAttribute <ShellModuleAttribute>(); if (moduleAttr == null) { context.Errorln($"assembly is not a shell module: '{assembly.FullName}'"); return(ModuleSpecification.ModuleSpecificationNotDefined); } var id = assembly.GetCustomAttribute <AssemblyTitleAttribute>()?.Title ?? throw new Exception($"module id missing in assembly '{assembly.ManifestModule.Name}' ('AssemblyTitle' attribute missing)"); var ver = assembly.GetCustomAttribute <AssemblyInformationalVersionAttribute>()?.InformationalVersion ?? throw new Exception($"module version missing in assembly '{assembly.ManifestModule.Name}' ('AssemblyInformationalVersion' attribute missing)"); var modKey = GetModuleLowerId(id, ver); if (_modules.ContainsKey(modKey)) { context.Errorln($"module already registered: {modKey} (path={assembly.FullName})"); return(ModuleSpecification.ModuleSpecificationNotDefined); } var typesCount = 0; var comTotCount = 0; var hooksCount = 0; foreach (var type in assembly.GetTypes()) { // register hooks var hookAttr = type.GetCustomAttribute <HooksAttribute>(); if (hookAttr != null) { // module,class owns hooks foreach (var mi in type.GetMethods(BindingFlags.Public | BindingFlags.Instance)) { var hook = mi.GetCustomAttribute <HookAttribute>(); if (hook != null) { ModuleHookManager.RegisterHook(context, hook.HookName, mi); hooksCount++; } } } // register commands var comsAttr = type.GetCustomAttribute <CommandsAttribute>(); var comCount = 0; if (comsAttr != null && type.GetInterface(typeof(ICommandsDeclaringType).FullName) != null) { comCount = ModuleCommandManager.RegisterCommandClass(context, type, false); } if (comCount > 0) { typesCount++; } comTotCount += comCount; } // register module var descAttr = assembly.GetCustomAttribute <AssemblyDescriptionAttribute>(); var description = (descAttr != null) ? descAttr.Description : ""; _modules.Add( modKey, moduleSpecification = new ModuleSpecification( modKey, Path.GetFileNameWithoutExtension(assembly.Location), description, assembly, new ModuleInfo( typesCount, comTotCount, hooksCount ) )); // run module hook init ModuleHookManager.InvokeHooks( context, Hooks.ModuleInit, (o) => { moduleSpecification.IsInitialized = true; } ); return(moduleSpecification); }
public CommandResult <string> NugetPush( CommandEvaluationContext context, [Parameter(0, "package (.nuget) file path")] FilePath pkgFile, [Parameter(1, "target server api key")] string apiKey, [Option("u", "push-url", "nuget server api push service url", true, true)] string url = PushUrl, [Option("p", "protocol-version", "nuget thir party client protocol version", true, true)] string protocolVersion = ProtocolVersion ) { var @return = ""; if (pkgFile.CheckExists(context)) { var ext = Path.GetExtension(pkgFile.FullName); var atExt = ".nupkg"; if (ext.ToLower() != atExt) { context.Errorln($"bad file extension: '{ext}', should be '{atExt}'"); } else { if (string.IsNullOrWhiteSpace(apiKey)) { context.Errorln($"api key is required and can't be empty"); } else { using var httpClient = new HttpClient(); using var request = new HttpRequestMessage(new HttpMethod("PUT"), url); request.Headers.Add("X-NuGet-ApiKey", apiKey); request.Headers.AcceptEncoding.ParseAdd("gzip,deflate"); request.Headers.Add("X-NuGet-Protocol-Version", protocolVersion); //request.Headers.Add("X-NuGet-Client-Version", "5.8.1"); //request.Headers.Add("user-agent", "NuGet Command Line / 5.8.1 (Microsoft Windows NT 10.0.19042.0)"); var content = new MultipartFormDataContent(); var fileContent = new ByteArrayContent(File.ReadAllBytes(pkgFile.FullName)); fileContent.Headers.ContentDisposition = new ContentDispositionHeaderValue( "form-data" ) { FileName = "package.nupkg" }; fileContent.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream"); content.Add(fileContent); request.Content = content; context.Out.Echo(context.ShellEnv.Colors.Log + $"PUT {PushUrl} ... "); var tsk = httpClient.SendAsync(request); var result = tsk.Result; if (result.IsSuccessStatusCode) { var res = result.Content.ReadAsStringAsync().Result; context.Out.Echoln(" Done(rdc)"); context.Out.Echo(ANSI.RSTXTA + ANSI.CPL(1) + ANSI.EL(ANSI.ELParameter.p2)); // TODO: add as ANSI combo @return = res; if (res != null) { if (!string.IsNullOrWhiteSpace(res)) { context.Out.Echoln(res); } } else { context.Warningln("quey result is empty"); } context.Warningln("quey result is empty"); if (result.StatusCode == HttpStatusCode.Created || result.StatusCode == HttpStatusCode.Accepted) { context.Out.Echoln($"package '{Path.GetFileName(pkgFile.FullName)}' has been successfully pushed"); } } else { context.Errorln($"can't get response content: {(int)result.StatusCode} {result.ReasonPhrase}"); } } } } return(new CommandResult <string>(@return)); }
public CommandVoidResult NewModule( CommandEvaluationContext context, [Parameter(0, "module ID")] string id, [Parameter(1, "module project repository url (if not set do net set project repository properties, thus the project repo is not connected to any remote repository)", true)] string repoUrl = null, [Option("o", "out", "output path", true, true)] DirectoryPath output = null, [Option("i", "in", "take parameters from json input file", true, true)] string inputFile = defaultSettingsFileName, [Option("f", "force", "delete target if already exists")] bool force = false, [Option("s", "skip-errors", "skip ant error if possible")] bool skipErrors = false, [Option(null, "no-push", "don't perform an initial push of project repo")] bool noPush = false, [Option("project template url", "modproj-tpl-url", "module project template url", true, true)] string url = moduleProjectTemplateRepositoryUrl, [Option(null, "preserve-curdir", "preserve current dir")] bool preserveCurrentDir = false ) { var o = context.Out; var c = context.ShellEnv.Colors; output ??= new DirectoryPath(Environment.CurrentDirectory); output = new DirectoryPath(Path.Combine(output.FullName, id)); var input = new FilePath(inputFile); var ectx = new EchoEvaluationContext(context); ectx.Options.LineBreak = true; CommandVoidResult result = CommandVoidResult.Instance; o.Echo(_title("shell module dotnet project generator")); #region download_pattern_project if (force && output.CheckExists()) { Directory.Delete(output.FullName, true); } o.Echoln(_subTitle("cloning module project repository", url)); o.Echo(_("into: ")); output.Echo(ectx); o.Echoln("(br)"); if (!ShellExec(context, skipErrors, "git", $"clone {url} {output.FullName}", out result)) { return(result); } #endregion #region setup project template properties if (!input.CheckExists(context)) { return(new CommandVoidResult(ReturnCode.Error)); } o.Echoln(_subTitle($"set project template properties", $"'{id}'")); string packageId = !string.IsNullOrWhiteSpace(repoUrl) ? Path.GetFileNameWithoutExtension(repoUrl) : null; string repoOwner = !string.IsNullOrWhiteSpace(repoUrl) ? Path.GetFileName(Path.GetDirectoryName(repoUrl)) : null; var settingsText = File.ReadAllText(input.FullName); var settings = JsonConvert .DeserializeObject <ModuleSettings>(settingsText) .AutoFill(id, packageId); settings.ModuleRepositoryUrl = repoUrl; settings.ModuleRepositoryOwner = repoOwner; o.Echoln(_subTitle("using settings", input.FullName)); settings.Echo(ectx); o.Echoln("(br)"); var items = fs.FindItems( context, output.FullName, "*", false, true, false, true, false, null, false, new FindCounts(), false); var fields = typeof(ModuleSettings).GetFields(); foreach (var item in items) { var path = item.FullName; if (item.IsFile && fs.IsTextFile(path)) { var tpl = path; _templateReplace(fields, settings, ref tpl); var txt = File.ReadAllText(path); if (tpl != path) { File.Delete(path); path = tpl; } tpl = txt + ""; _templateReplace(fields, settings, ref tpl); if (tpl != txt) { File.WriteAllText(path, tpl); } } } void _deleteIfExists(string n) { if (File.Exists(n)) { File.Delete(n); } } _deleteIfExists(Path.Combine(output.FullName, "templateInfo.txt")); _deleteIfExists(Path.Combine(output.FullName, "./module-settings.json")); #endregion #region setup project repository o.Echoln(_subTitle("setup project repository", url)); o.Echoln(); var curDir = Environment.CurrentDirectory; Environment.CurrentDirectory = output.FullName; if (!ShellExec(context, skipErrors, "git", "remote remove origin", out result)) { return(result); } if (!string.IsNullOrWhiteSpace(settings.ModuleRepositoryUrl)) { if (!ShellExec(context, skipErrors, "git", $"remote add origin {settings.ModuleRepositoryUrl}", out result)) { return(result); } // check this if (!noPush && !ShellExec(context, skipErrors, "git", "push --set-upstream origin main", out result)) { return(result); } } #endregion #region restore & build project o.Echoln(_subTitle("restore & build module project", "")); o.Echoln(); if (!ShellExec(context, skipErrors, "dotnet", "build", out result)) { return(result); } #endregion if (preserveCurrentDir) { Environment.CurrentDirectory = curDir; } o.Echoln(_subTitle($"module project has been generated", id)); return(result ?? CommandVoidResult.Instance); }
public CommandResult <QueryResultRoot> NugetQuery( CommandEvaluationContext context, [Parameter("the search terms to used to filter packages", true)] string query, [Option("s", "skip", "the number of results to skip, for pagination", true, true)] int skip = -1, [Option("t", "take", "the number of results to return, for pagination", true, true)] int take = -1, [Option("r", "pre-release", "true or false determining whether to include pre-release packages (default no)")] bool preRelease = false, [Option("l", "sem-ver-level", "a SemVer 1.0.0 version string", true, true)] string semVerLevel = "2.0.0", [Option("p", "package-type", "the package type to use to filter packages (added in SearchQueryService/3.5.0)", true, true)] string packageType = null, [Option("u", "query-url", "nuget server api query service template url", true, true)] string url = QueryUrl ) { QueryResultRoot @return = null; query ??= ""; var queryString = url.Replace("{QUERY}", query.Trim()); if (skip > -1) { queryString = queryString.Replace("{SKIP}", skip + ""); } if (take > -1) { queryString = queryString.Replace("{TAKE}", take + ""); } queryString = queryString.Replace("{PRERELEASE}", preRelease.ToString().ToLower()); if (semVerLevel != null) { queryString = queryString.Replace("{SEMVERLEVEL}", semVerLevel); } if (packageType != null) { queryString = queryString.Replace("{PACKAGETYPE}", packageType); } queryString = queryString .Replace("&skip={SKIP}", "") .Replace("&take={TAKE}", "") .Replace("&prerelease={PRERELEASE}", "") .Replace("&semVerLevel={SEMVERLEVEL}", "") .Replace("&packageType={PACKAGETYPE}", ""); context.Out.Echo(context.ShellEnv.Colors.Log + $"GET {queryString} ... "); using var httpClient = new HttpClient(); using var request = new HttpRequestMessage(new HttpMethod("GET"), queryString); var tsk = httpClient.SendAsync(request); var result = tsk.Result; if (result.IsSuccessStatusCode) { var res = result.Content.ReadAsStringAsync().Result; context.Out.Echoln(" Done(rdc)"); context.Out.Echo(ANSI.RSTXTA + ANSI.CPL(1) + ANSI.EL(ANSI.ELParameter.p2)); // TODO: add as ANSI combo var obj = JsonConvert.DeserializeObject <QueryResultRoot>(res); @return = obj; if (obj != null && obj.Data != null) { obj.Echo(new EchoEvaluationContext(context.Out, context)); } else { context.Errorln("invalid json"); } } else { context.Errorln($"can't get response content: {result.ReasonPhrase}"); } return(new CommandResult <QueryResultRoot>(@return)); }
public int RunBatch(CommandEvaluationContext context, string path) { var(lines, _, _) = TextFileReader.ReadAllLines(path); return(RunBatch(context, lines)); }
public void RunBatch(CommandEvaluationContext context, string path) { var(lines, eol, separator) = TextFileReader.ReadAllLines(path); RunBatch(context, lines); }
static TextFileInfo PrintFile( CommandEvaluationContext context, FilePath file, bool hideLineNumbers, bool raw ) { const int cl = -14; string quit = $"{context.ShellEnv.Colors.ParameterName}{$"q|Q",cl}{context.ShellEnv.Colors.Default}quit"; string help = $"{context.ShellEnv.Colors.ParameterName}{$"h|H",cl}{context.ShellEnv.Colors.Default}print this help"; string scrollnext = $"{context.ShellEnv.Colors.ParameterName}{$"space",cl}{context.ShellEnv.Colors.Default}display next lines of text, according to current screen size"; string scrolllinedown = $"{context.ShellEnv.Colors.ParameterName}{$"down arrow",cl}{context.ShellEnv.Colors.Default}scroll one line down"; string scrolllineup = $"{context.ShellEnv.Colors.ParameterName}{$"up arrow",cl}{context.ShellEnv.Colors.Default}scroll one line up"; string pagedown = $"{context.ShellEnv.Colors.ParameterName}{$"right arrow",cl}{context.ShellEnv.Colors.Default}jump one page down, according to current screen size"; string pageup = $"{context.ShellEnv.Colors.ParameterName}{$"left arrow",cl}{context.ShellEnv.Colors.Default}jump one page up, according to current screen size"; string totop = $"{context.ShellEnv.Colors.ParameterName}{$"t|T",cl}{context.ShellEnv.Colors.Default}jump to the top of the file"; string toend = $"{context.ShellEnv.Colors.ParameterName}{$"e|E",cl}{context.ShellEnv.Colors.Default}jump to the end of the file"; var inputMaps = new List <InputMap> { new InputMap("q", quit), new InputMap("h", help), new InputMap(" ", scrollnext), new InputMap((str, key) => key.Key == ConsoleKey.DownArrow?InputMap.ExactMatch:InputMap.NoMatch, scrolllinedown), new InputMap((str, key) => key.Key == ConsoleKey.UpArrow?InputMap.ExactMatch:InputMap.NoMatch, scrolllineup), new InputMap((str, key) => key.Key == ConsoleKey.RightArrow?InputMap.ExactMatch:InputMap.NoMatch, pagedown), new InputMap((str, key) => key.Key == ConsoleKey.LeftArrow?InputMap.ExactMatch:InputMap.NoMatch, pageup), new InputMap("t", totop), new InputMap("e", toend) }; var fileEncoding = file.GetEncoding(Encoding.Default); var(rlines, filePlatform, eol) = ReadAllLines(file.FullName); var lines = rlines.ToArray(); var nblines = lines.Length; var infos = $" ({Plur("line", nblines)},encoding={(fileEncoding != null ? fileEncoding.EncodingName : "?")},eol={filePlatform})"; var n = file.Name.Length + context.CommandLineProcessor.Console.TabLength + infos.Length; var sep = "".PadRight(n + 1, '-'); context.Out.Echoln($"{context.ShellEnv.Colors.TitleBar}{sep}"); context.Out.Echoln($"{context.ShellEnv.Colors.TitleBar} {file.Name}{context.ShellEnv.Colors.TitleDarkText}{infos.PadRight(n - file.Name.Length, ' ')}"); context.Out.Echoln($"{context.ShellEnv.Colors.TitleBar}{sep}{context.ShellEnv.Colors.Default}"); var preambleHeight = 3; var linecollength = nblines.ToString().Length; var pos = 0; bool end = false; int y = 0, x = 0; var actualWorkArea = context.CommandLineProcessor.Console.ActualWorkArea(); int maxk = actualWorkArea.Bottom - actualWorkArea.Top + 1; int k = maxk; bool endReached = false; bool topReached = true; bool skipPrint = false; bool scroll1down = false; bool forcePrintInputBar = false; int decpos = 0; while (!end) { var h = k - 1 - preambleHeight; var curNbLines = Math.Min(nblines, h); var percent = nblines == 0 ? 100 : Math.Ceiling((double)(Math.Min(curNbLines + pos + decpos, nblines)) / (double)nblines * 100d); int i = 0; if (!skipPrint) { lock (context.Out) { context.Out.HideCur(); while (i < curNbLines && pos + decpos + i < nblines) { if (context.CommandLineProcessor.CancellationTokenSource.IsCancellationRequested) { return(new TextFileInfo(file, rlines, filePlatform, eol)); } var prefix = hideLineNumbers ? "" : (context.ShellEnv.Colors.Dark + " " + (pos + decpos + i + 1).ToString().PadRight(linecollength, ' ') + " "); context.Out.Echo(prefix + context.ShellEnv.Colors.Default); context.Out.Echo(lines[pos + decpos + i], true, raw); i++; } context.Out.ShowCur(); y = sc.CursorTop; x = sc.CursorLeft; endReached = pos + i >= nblines; topReached = pos == 0; } } var inputText = $"--more--({percent}%)"; var action = end ? quit : InputBar(context, inputText, inputMaps); end = (string)action == quit; var oldpos = pos; if ((string)action == scrollnext) { k = maxk; pos += k - 1 - preambleHeight; } if ((string)action == scrolllinedown && !endReached) { if (!scroll1down) { scroll1down = true; decpos = k - 1 - preambleHeight - 1; } pos++; k = 2; } else { scroll1down = false; decpos = 0; } if ((string)action == totop) { k = maxk; pos = 0; if (pos != oldpos) { context.Out.ClearScreen(); } } if ((string)action == toend) { k = maxk; pos = Math.Max(0, nblines - maxk + 1); if (pos != oldpos) { context.Out.ClearScreen(); } } if ((string)action == scrolllineup && !topReached) { context.Out.ClearScreen(); k = maxk; pos = Math.Max(0, pos - 1); } if ((string)action == pagedown && !endReached) { context.Out.ClearScreen(); k = maxk; pos += k - 1 - preambleHeight; } if ((string)action == pageup && !topReached) { context.Out.ClearScreen(); k = maxk; pos = Math.Max(0, pos - k + 1); } if ((string)action == help) { var sepw = inputMaps.Select(x => ((string)x.Code).Length).Max(); var hsep = "".PadRight(sepw + 10, '-'); context.Out.Echoln(Br + hsep + Br); inputMaps.ForEach(x => context.Out.Echoln((string)x.Code + Br)); context.Out.Echoln(hsep); forcePrintInputBar = true; } preambleHeight = 0; skipPrint = oldpos == pos; lock (context.Out) { sc.CursorLeft = x; if (forcePrintInputBar || !skipPrint || end) { context.Out.Echo("".PadLeft(inputText.Length, ' ')); sc.CursorLeft = x; forcePrintInputBar = false; } } } return(new TextFileInfo(file, rlines, filePlatform, eol)); }
void PrintCommandHelp( CommandEvaluationContext context, CommandSpecification com, bool shortView = false, bool list = false, int maxcnamelength = -1, int maxcmdtypelength = -1, int maxmodlength = -1, bool singleout = false) { #pragma warning disable IDE0071 // Simplifier l’interpolation #pragma warning disable IDE0071WithoutSuggestion // Simplifier l’interpolation if (maxcnamelength == -1) { maxcnamelength = com.Name.Length + 1; } if (maxcmdtypelength == -1) { maxcmdtypelength = com.DeclaringTypeShortName.Length + 1; } var col = singleout? "": "".PadRight(maxcnamelength, ' '); var f = GetCmd(EchoDirectives.f + "", DefaultForeground.ToString().ToLower()); if (list) { if (!shortView) { context.Out.Echoln($"{Darkcyan}{com.ModuleName.PadRight(maxmodlength, ' ')} {com.DeclaringTypeShortName.PadRight(maxcmdtypelength, ' ')}{Tab}{ColorSettings.Highlight}{com.Name.PadRight(maxcnamelength, ' ')}{Tab}{f}{com.Description}{ColorSettings.Default}"); } else { context.Out.Echoln($"{ColorSettings.Highlight}{com.Name.PadRight(maxcnamelength, ' ')}{f}{Tab}{com.Description}{ColorSettings.Default}"); } } else { if (singleout) { context.Out.Echoln(com.Description); if (com.ParametersCount > 0) { context.Out.Echo($"{Br}{col}{ColorSettings.Label}syntax: {f}{com.ToColorizedString()}{(!shortView ? Br : "")}"); } context.Out.Echoln(GetPrintableDocText(com.LongDescription, list, shortView, 0)); } else { context.Out.Echoln($"{com.Name.PadRight(maxcnamelength, ' ')}{com.Description}"); if (com.ParametersCount > 0) { context.Out.Echo($"{Br}{col}{ColorSettings.Label}syntax: {f}{com.ToColorizedString()}{(!shortView ? Br : "")}"); } context.Out.Echo(GetPrintableDocText(com.LongDescription, list, shortView, maxcnamelength)); } } if (!list) { if (com.ParametersCount > 0) { if (!shortView) { var mpl = com.ParametersSpecifications.Values.Select(x => x.Dump(false).Length).Max() + TabLength; foreach (var p in com.ParametersSpecifications.Values) { var ptype = (!p.IsOption && p.HasValue) ? $"of type: {Darkyellow}{p.ParameterInfo.ParameterType.Name}{f}" : ""; var pdef = (p.HasValue && p.IsOptional && p.HasDefaultValue && p.DefaultValue != null && (!p.IsOption || p.ParameterValueTypeName != typeof(bool).Name)) ? ((ptype != ""?". ":"") + $"default value: {Darkyellow}{DumpAsText(p.DefaultValue)}{f}") : ""; var supdef = $"{ptype}{pdef}"; context.Out.Echoln($"{col}{Tab}{p.ToColorizedString(false)}{"".PadRight(mpl - p.Dump(false).Length, ' ')}{p.Description}"); if (!string.IsNullOrWhiteSpace(supdef)) { context.Out.Echoln($"{col}{Tab}{" ".PadRight(mpl)}{supdef}"); } } if (string.IsNullOrWhiteSpace(com.Documentation)) { context.Out.Echoln(); } context.Out.Echo(GetPrintableDocText(com.Documentation, list, shortView, singleout ? 0 : maxcnamelength)); } else { context.Out.Echoln(GetPrintableDocText(com.Documentation, list, shortView, singleout ? 0 : maxcnamelength)); } } if (!shortView) { context.Out.Echoln($"{col}{ColorSettings.Label}type : {ColorSettings.DarkLabel}{com.DeclaringTypeShortName}"); context.Out.Echoln($"{col}{ColorSettings.Label}module: {ColorSettings.DarkLabel}{com.ModuleName}{ColorSettings.Default}"); } } #pragma warning restore IDE0071WithoutSuggestion // Simplifier l’interpolation #pragma warning restore IDE0071 // Simplifier l’interpolation }
public CommandResult <(List <(FileSystemPath source, FileSystemPath target)> items, FindCounts counts)> Mv( CommandEvaluationContext context, [Parameter("source: file/directory or several corresponding to a wildcarded path")] WildcardFilePath source, [Parameter(1, "destination: a file or a directory")] FileSystemPath dest, [Option("i", "prompt before overwrite")] bool interactive, [Option("v", "explain what is being done")] bool verbose ) { if (source.CheckExists()) { var counts = new FindCounts(); var items = FindItems(context, source.FullName, source.WildCardFileName ?? "*", true, true, false, true, false, null, false, counts, false, false); var sourceCount = items.Count; List <(FileSystemPath src, FileSystemPath tgt)> r = new List <(FileSystemPath src, FileSystemPath tgt)>(); if (sourceCount > 1) { if (dest.CheckExists()) { if (!dest.IsDirectory) { Errorln("dest must be a directory"); return(new CommandResult <(List <(FileSystemPath, FileSystemPath)> items, FindCounts counts)>( (new List <(FileSystemPath, FileSystemPath)> { (source, dest) }, counts), ReturnCode.Error )); } else { // move multiple source to dest foreach (var item in items) { var msg = $"move {item.GetPrintableName()} to {dest.GetPrintableName()}"; if (!interactive || Confirm("mv: " + msg)) { if (source.IsFile) { var newdest = Path.Combine(dest.FullName, item.Name); r.Add((item, new FileSystemPath(newdest))); File.Move(item.FullName, newdest); } else { var newdest = Path.Combine(dest.FullName, item.Name); Directory.Move(item.FullName, newdest); r.Add((item, new DirectoryPath(newdest))); } if (verbose) { context.Out.Echoln(msg.Replace("move ", "moved ")); } } } } } } else { if (dest.CheckExists(false)) { if (dest.IsDirectory) { // move one source to dest var msg = $"move {source.GetPrintableNameWithWlidCard()} to {dest.GetPrintableName()}"; if (!interactive || Confirm("mv: " + msg)) { if (source.IsFile) { var newdest = Path.Combine(dest.FullName, source.NameWithWildcard); File.Move(source.FullNameWithWildcard, newdest); r.Add((new FilePath(source.FullNameWithWildcard), new FilePath(newdest))); } else { var newdest = Path.Combine(dest.FullName, source.NameWithWildcard); Directory.Move(source.FullName, newdest); r.Add((source, new DirectoryPath(newdest))); } if (verbose) { context.Out.Echoln(msg.Replace("move ", "moved ")); } } } else { // rename source (file) to dest (overwrite dest) var msg = $"rename {source.GetPrintableNameWithWlidCard()} to {dest.GetPrintableName()}"; if (!interactive || Confirm("mv: " + msg)) { dest.FileSystemInfo.Delete(); File.Move(source.FullNameWithWildcard, dest.FullName); r.Add((new FilePath(source.FullNameWithWildcard), dest)); if (verbose) { context.Out.Echoln(msg.Replace("rename ", "renamed ")); } } } } else { // rename source to dest var msg = $"rename {source.GetPrintableNameWithWlidCard()} to {dest.GetPrintableName()}"; if (!interactive || Confirm("mv: " + msg)) { if (source.IsFile) { File.Move(source.FullNameWithWildcard, dest.FullName); r.Add((new FilePath(source.FullNameWithWildcard), dest)); } else { Directory.Move(source.FullName, dest.FullName); r.Add((source, dest)); } if (verbose) { context.Out.Echoln(msg.Replace("rename ", "renamed ")); } } } } return(new CommandResult <(List <(FileSystemPath source, FileSystemPath target)> items, FindCounts counts)> ((r, counts))); } else { return(new CommandResult <(List <(FileSystemPath, FileSystemPath)> items, FindCounts counts)> ((new List <(FileSystemPath, FileSystemPath)> { (source, null) }, new FindCounts()))); } }
public CommandResult <List <CommandsModule> > Module( CommandEvaluationContext context, [Option("l", "load a module from the given path", true, true)] FilePath loadModulePath = null, [Option("u", "unload the module having the given name ", true, true)] string unloadModuleName = null ) { var f = ColorSettings.Default.ToString(); if (loadModulePath == null && unloadModuleName == null) { var col1length = context.CommandLineProcessor.Modules.Values.Select(x => x.Name.Length).Max() + 1; foreach (var kvp in context.CommandLineProcessor.Modules) { context.Out.Echoln($"{Darkcyan}{kvp.Value.Name.PadRight(col1length, ' ')}{f}{kvp.Value.Description} [types count={Cyan}{kvp.Value.TypesCount}{f} commands count={Cyan}{kvp.Value.CommandsCount}{f}]"); context.Out.Echoln($"{"".PadRight(col1length, ' ')}{ColorSettings.Label}assembly:{ColorSettings.HalfDark}{kvp.Value.Assembly.FullName}"); context.Out.Echoln($"{"".PadRight(col1length, ' ')}{ColorSettings.Label}path: {ColorSettings.HalfDark}{kvp.Value.Assembly.Location}"); } return(new CommandResult <List <CommandsModule> >(context.CommandLineProcessor.Modules.Values.ToList())); } if (loadModulePath != null) { if (loadModulePath.CheckExists()) { var a = Assembly.LoadFrom(loadModulePath.FileSystemInfo.FullName); var(typesCount, commandsCount) = context.CommandLineProcessor.RegisterCommandsAssembly(context, a); if (commandsCount == 0) { Errorln("no commands have been loaded"); return(new CommandResult <List <CommandsModule> >(ReturnCode.Error)); } else { context.Out.Echoln($"loaded {ColorSettings.Numeric}{Plur("command", commandsCount, f)} in {ColorSettings.Numeric}{Plur("type", typesCount, f)}"); } } else { return(new CommandResult <List <CommandsModule> >(ReturnCode.Error)); } } if (unloadModuleName != null) { if (context.CommandLineProcessor.Modules.Values.Any(x => x.Name == unloadModuleName)) { var(typesCount, commandsCount) = context.CommandLineProcessor.UnregisterCommandsAssembly(context, unloadModuleName); if (commandsCount == 0) { Errorln("no commands have been unloaded"); return(new CommandResult <List <CommandsModule> >(ReturnCode.Error)); } else { context.Out.Echoln($"unloaded {ColorSettings.Numeric}{Plur("command", commandsCount, f)} in {ColorSettings.Numeric}{Plur("type", typesCount, f)}"); } } else { Errorln($"commands module '{unloadModuleName}' not registered"); return(new CommandResult <List <CommandsModule> >(ReturnCode.Error)); } } return(new CommandResult <List <CommandsModule> >()); }
public EchoEvaluationContext(CommandEvaluationContext context) { Out = context.Out; CommandEvaluationContext = context; Options = new FormatingOptions(); }
public CommandVoidResult Help( CommandEvaluationContext context, [Option("s", "set short view: decrase output details")] bool shortView, [Option("v", "set verbose view: increase output details")] bool verboseView, [Option("all", "list all commands")] bool all, [Option("t", "filter commands list by command declaring type. if t is * list types", true, true)] string type, [Option("m", "filter commands list by module name. if m is * list modules", true, true)] string module, [Parameter("output help for the command with name 'commandName'", true)] string commandName ) { var hascn = !string.IsNullOrWhiteSpace(commandName); var list = !all && !hascn; var cmds = context.CommandLineProcessor.AllCommands.AsQueryable(); if (hascn) { cmds = cmds.Where(x => x.Name.Equals(commandName, CommandLineParser.SyntaxMatchingRule)); } if (cmds.Count() > 0) { if (!string.IsNullOrWhiteSpace(type)) { if (type != "*" && !context.CommandLineProcessor.CommandDeclaringShortTypesNames.Contains(type)) { Errorln($"unknown command declaring type: '{type}'"); return(new CommandVoidResult(ReturnCode.Error)); } shortView = !verboseView; if (type != "*") { cmds = cmds.Where(x => x.DeclaringTypeShortName == type); } else { var typenames = context.CommandLineProcessor.CommandDeclaringTypesNames.ToList(); var typelst = typenames.Select(x => Type.GetType(x)).ToList(); typelst.Sort((x, y) => x.Name.CompareTo(y.Name)); var sfx = "Commands"; string TypeName(Type type) { var s = shortView ? type.Name : type.FullName; if (shortView && s.EndsWith(sfx)) { s = s.Substring(0, s.Length - sfx.Length); } return(s); } var maxtl = typelst.Select(x => TypeName(x).Length).Max(); foreach (var typ in typelst) { var cmdattr = typ.GetCustomAttribute <CommandsAttribute>(); context.Out.Echoln(Darkcyan + TypeName(typ).PadRight(maxtl) + Tab + DefaultForegroundCmd + cmdattr.Description); } return(new CommandVoidResult()); } } if (cmds.Count() > 0 && !string.IsNullOrWhiteSpace(module)) { if (module != "*" && !context.CommandLineProcessor.Modules.Values.Select(x => x.Name).Contains(module)) { Errorln($"unknown command module: '{module}'"); return(new CommandVoidResult(ReturnCode.Error)); } shortView = !verboseView; if (module != "*") { cmds = cmds.Where(x => x.ModuleName == module); } else { var mods = context.CommandLineProcessor.Modules; var modnames = mods.Values.Select(x => x.Name).ToList(); modnames.Sort(); var maxml = modnames.Select(x => x.Length).Max(); foreach (var modname in modnames) { context.Out.Echoln(Darkcyan + modname.PadRight(maxml) + Tab + DefaultForegroundCmd + mods[modname].Description); } return(new CommandVoidResult()); } } var ncmds = cmds.ToList(); ncmds.Sort(new Comparison <CommandSpecification>((x, y) => x.Name.CompareTo(y.Name))); cmds = ncmds.AsQueryable(); if (cmds.Count() > 0) { var maxcmdlength = cmds.Select(x => x.Name.Length).Max() + 1; var maxcmdtypelength = cmds.Select(x => x.DeclaringTypeShortName.Length).Max() + 1; var maxmodlength = cmds.Select(x => Path.GetFileNameWithoutExtension(x.MethodInfo.DeclaringType.Assembly.Location).Length).Max() + 1; int n = 0; if (list) { shortView = !verboseView; } foreach (var cmd in cmds) { if (!list && n > 0) { context.Out.Echoln(); } PrintCommandHelp(context, cmd, shortView, list, maxcmdlength, maxcmdtypelength, maxmodlength, !string.IsNullOrWhiteSpace(commandName)); n++; } } } else { Errorln($"Command not found: '{commandName}'"); return(new CommandVoidResult(ReturnCode.Error)); } return(new CommandVoidResult()); }