static void Main1(string[] args) { Thread.CurrentThread.CurrentCulture = new CultureInfo("en-US"); Thread.CurrentThread.CurrentUICulture = new CultureInfo("en-US"); IConsole console = new DotNetConsole(); Grid grid = ElementFactory.CreateGrid(i => i .Target(console) .Size(1, 4) ); grid.Add(0, 0, new Text("Publish channel:")); grid.Add(0, 1, new Button("Debug")); grid.Add(0, 2, new Button("Keyuser")); grid.Add(0, 3, new Button("Release")); foreach (var element in grid.EnumerateElements()) { if (element != null) { element.OnEnterPressed += ButtonClick; } } while (true) { grid.Render(); grid.HandleInput(); } }
static void Main2(string[] args) { IConsole console = new DotNetConsole(); Grid grid = ElementFactory.CreateGrid(i => i .Target(console) .Size(4, 4) ); grid.Add(0, 0, ElementFactory.CreateText(i => i .Text("0,0") .Colors(Color.DarkYellow, Color.DarkBlue) )); grid.Add(0, 1, new Button("0,1")); grid.Add(2, 0, new Button("2,0")); grid.Add(1, 1, new Button("1,1")); grid.Add(1, 2, new Button("1,2")); grid.Add(2, 1, new Button("2,1")); grid.Add(2, 2, ElementFactory.CreateButton(i => i .Text("2.2") .Colors(Color.DarkRed, Color.Blue) .Highlight(Color.Green, Color.Magenta) )); grid.Add(1, 0, new Text("Text asdf")); Grid subGrid = ElementFactory.CreateGrid(i => i .Target(console) .Size(1, 4) .Text("Deploy application") .Colors(Color.Red, Color.Black) .Highlight(Color.Black, Color.Red) ); subGrid.Add(0, 0, new Button("Debug")); subGrid.Add(0, 1, new Button("Keyuser")); subGrid.Add(0, 2, ElementFactory.CreateButton(i => i .Text("Release") .Pressed((sender, param) => { System.Diagnostics.Debug.WriteLine("Release button pressed. Param: " + (int)param); }, 12) )); grid.Add(0, 2, subGrid); while (true) { grid.Render(); grid.HandleInput(); } }
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)); }
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 + cons.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 = DotNetConsole.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(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)); }
public CommandResult <(List <FileSystemPath> items, FindCounts counts)> Dir( CommandEvaluationContext context, [Parameter("path where to list files and folders. if not specified is set to the current directory. use wildcards * and ? to filter files and folders names", true)] WildcardFilePath path, [Option("n", "name", "names only: do not print file system attributes")] bool noattributes, [Option("r", "recurse", "also list files and folders in sub directories. force display files full path")] bool recurse, [Option("w", "wide", "displays file names on several columns so output fills console width (only if not recurse mode). disable print of attributes")] bool wide, [Option("f", "file", "filter list on files (exclude directories). avoid -d")] bool filesOnly, [Option("d", "dir", "filter list on directories (exclude files)")] bool dirsOnly, [Option("s", "sort", "sort list of files and folders. default is alphabetic, mixing files and folders", true, true)] DirSort sort = DirSort.dir | DirSort.name ) { var r = new List <FileSystemPath>(); path ??= new WildcardFilePath(Environment.CurrentDirectory); if (path.CheckExists(context)) { var counts = new FindCounts(); var items = FindItems(context, path.FullName, path.WildCardFileName ?? "*", !recurse, true, false, !noattributes, !recurse, null, false, counts, false, false); if (filesOnly) { dirsOnly = false; } if (filesOnly) { items = items.Where(x => x.IsFile).ToList(); } if (dirsOnly) { items = items.Where(x => x.IsDirectory).ToList(); } // apply sorts - default (.net) is name (==DirSort.name==1) - possible DirSort.not_specified==0 == default sort by name if (sort != DirSort.not_specified && sort != DirSort.name) { IEnumerable <IGrouping <string, FileSystemPath> > grp = null; if (sort.HasFlag(DirSort.ext)) { grp = items.GroupBy((x) => Path.GetExtension(x.FullName)); } else if (sort.HasFlag(DirSort.file)) { grp = items.GroupBy((x) => x.IsDirectory + ""); } else if (sort.HasFlag(DirSort.dir)) { grp = items.GroupBy((x) => x.IsFile + ""); } else if (sort.HasFlag(DirSort.size)) { grp = items.GroupBy((x) => !x.IsFile + ""); } var lst = grp.ToList(); lst.Sort((x, y) => x.Key.CompareTo(y.Key)); // sort alpha if (!sort.HasFlag(DirSort.file) && !sort.HasFlag(DirSort.dir) && !sort.HasFlag(DirSort.size) && sort.HasFlag(DirSort.rev)) { lst.Reverse(); } items.Clear(); foreach (var g in lst) { var glst = g.ToList(); if (!sort.HasFlag(DirSort.size)) { glst.Sort((x, y) => x.FullName.CompareTo(y.FullName)); // sort alpha } else { glst.Sort((x, y) => x.Length.CompareTo(y.Length)); // sort size } if (sort.HasFlag(DirSort.rev)) { glst.Reverse(); } items.AddRange(glst); } } var f = DefaultForegroundCmd; long totFileSize = 0; var cancellationTokenSource = new CancellationTokenSource(); if (wide) { noattributes = true; } // here we self handle the console Cancel event so we can output a partial result even if the seek phasis has been broke. print can also be broke. // TODO: seems there is now a simple way to do this. Just use the context cancellation token (as in findItems) : // TODO: if (context.CommandLineProcessor.CancellationTokenSource.Token.IsCancellationRequested) // then cancel com void postCmd(object o, EventArgs e) { sc.CancelKeyPress -= cancelCmd; context.Out.Echoln($"{Tab}{context.ShellEnv.Colors.Numeric}{Plur("file", counts.FilesCount, f),-30}{HumanFormatOfSize(totFileSize, 2, " ", context.ShellEnv.Colors.Numeric.ToString(), f)}"); context.Out.Echoln($"{Tab}{context.ShellEnv.Colors.Numeric}{Plur("folder", counts.FoldersCount, f),-30}{Drives.GetDriveInfo(path.FileSystemInfo.FullName, false, context.ShellEnv.Colors.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.Echo( new EchoEvaluationContext( context.Out, context, new FileSystemPathFormattingOptions( !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)); }