From c04703f5d6a5e12d74fb27fe831028f5b2f804cc Mon Sep 17 00:00:00 2001 From: Thomas Nind <31306100+tznind@users.noreply.github.com> Date: Sat, 13 May 2023 07:14:19 +0100 Subject: [PATCH] Fixes #2617 - Support for Nerd icons for FileDialog (#2613) * Add explicit file name unicode mappings * Added nerd file extensions * Add folder icon * Added tests and attribution * Fix tree view not using System.IO.Abstractions * Make FileDialog tree use IconGetter * Added context to IconGetter * Make Nerd a config setting * Fix typo in attribution * tidy up * Change open folder check to null or whitespace * Update class diagram to show new classes * Rename configuration property NerdFonts and set it to ThemeScope * Move NerdFonts setting to ConsoleDriver * Move NerdFonts setting to NerdFonts class and rename Enable --------- Co-authored-by: Tig --- Terminal.Gui/ConsoleDrivers/ConsoleDriver.cs | 1 + .../FileServices/FileDialogIconGetterArgs.cs | 35 + .../FileDialogIconGetterContext.cs | 18 + .../FileServices/FileDialogRootTreeNode.cs | 5 +- Terminal.Gui/FileServices/FileDialogStyle.cs | 44 +- .../FileServices/FileDialogTreeBuilder.cs | 38 +- Terminal.Gui/Views/FileDialog.cd | 59 +- Terminal.Gui/Views/FileDialog.cs | 14 +- Terminal.Gui/Views/FileDialogTableSource.cs | 7 +- Terminal.Gui/Views/NerdFonts.cs | 790 ++++++++++++++++++ UICatalog/Scenarios/FileDialogExamples.cs | 37 +- UnitTests/FileServices/NerdFontsTests.cs | 37 + 12 files changed, 1042 insertions(+), 43 deletions(-) create mode 100644 Terminal.Gui/FileServices/FileDialogIconGetterArgs.cs create mode 100644 Terminal.Gui/FileServices/FileDialogIconGetterContext.cs create mode 100644 Terminal.Gui/Views/NerdFonts.cs create mode 100644 UnitTests/FileServices/NerdFontsTests.cs diff --git a/Terminal.Gui/ConsoleDrivers/ConsoleDriver.cs b/Terminal.Gui/ConsoleDrivers/ConsoleDriver.cs index 597e85c01..5445d24bd 100644 --- a/Terminal.Gui/ConsoleDrivers/ConsoleDriver.cs +++ b/Terminal.Gui/ConsoleDrivers/ConsoleDriver.cs @@ -685,6 +685,7 @@ namespace Terminal.Gui { /// There are currently three implementations: (for Unix and Mac), , and that uses the .NET Console API. /// public abstract class ConsoleDriver { + /// /// The handler fired when the terminal is resized. /// diff --git a/Terminal.Gui/FileServices/FileDialogIconGetterArgs.cs b/Terminal.Gui/FileServices/FileDialogIconGetterArgs.cs new file mode 100644 index 000000000..be626d395 --- /dev/null +++ b/Terminal.Gui/FileServices/FileDialogIconGetterArgs.cs @@ -0,0 +1,35 @@ +using System.IO.Abstractions; + +namespace Terminal.Gui { + + /// + /// Arguments for the delegate + /// + public class FileDialogIconGetterArgs { + + /// + /// Creates a new instance of the class + /// + public FileDialogIconGetterArgs (FileDialog fileDialog, IFileSystemInfo file, FileDialogIconGetterContext context) + { + FileDialog = fileDialog; + File = file; + Context = context; + } + + /// + /// Gets the dialog that requires the icon. + /// + public FileDialog FileDialog { get; } + + /// + /// Gets the file/folder for which the icon is required. + /// + public IFileSystemInfo File { get; } + + /// + /// Gets the context in which the icon will be used in. + /// + public FileDialogIconGetterContext Context { get; } + } +} \ No newline at end of file diff --git a/Terminal.Gui/FileServices/FileDialogIconGetterContext.cs b/Terminal.Gui/FileServices/FileDialogIconGetterContext.cs new file mode 100644 index 000000000..c567d7db6 --- /dev/null +++ b/Terminal.Gui/FileServices/FileDialogIconGetterContext.cs @@ -0,0 +1,18 @@ +namespace Terminal.Gui { + /// + /// Describes the context in which icons are being sought + /// during . + /// + public enum FileDialogIconGetterContext { + + /// + /// Icon will be used in the tree view + /// + Tree, + + /// + /// Icon will be used in the main table area of the dialog + /// + Table + } +} \ No newline at end of file diff --git a/Terminal.Gui/FileServices/FileDialogRootTreeNode.cs b/Terminal.Gui/FileServices/FileDialogRootTreeNode.cs index e8bf1b32a..6c8f97091 100644 --- a/Terminal.Gui/FileServices/FileDialogRootTreeNode.cs +++ b/Terminal.Gui/FileServices/FileDialogRootTreeNode.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using System.IO; +using System.IO.Abstractions; namespace Terminal.Gui { @@ -22,7 +23,7 @@ namespace Terminal.Gui { /// /// /// - public FileDialogRootTreeNode (string displayName, DirectoryInfo path) + public FileDialogRootTreeNode (string displayName, IDirectoryInfo path) { this.DisplayName = displayName; this.Path = path; @@ -37,7 +38,7 @@ namespace Terminal.Gui { /// Gets the path that should be shown/explored when selecting this node /// of the tree. /// - public DirectoryInfo Path { get; } + public IDirectoryInfo Path { get; } /// /// Returns a string representation of this instance (). diff --git a/Terminal.Gui/FileServices/FileDialogStyle.cs b/Terminal.Gui/FileServices/FileDialogStyle.cs index 2bb58c62a..74f92b243 100644 --- a/Terminal.Gui/FileServices/FileDialogStyle.cs +++ b/Terminal.Gui/FileServices/FileDialogStyle.cs @@ -15,6 +15,7 @@ namespace Terminal.Gui { /// Stores style settings for . /// public class FileDialogStyle { + readonly IFileSystem _fileSystem; /// /// Gets or sets the default value to use for . @@ -35,7 +36,7 @@ namespace Terminal.Gui { /// should be used for different file types/directories. Defaults /// to false. /// - public bool UseColors { get; set; } + public bool UseColors { get; set; } = DefaultUseColors; /// /// Gets or sets the culture to use (e.g. for number formatting). @@ -155,7 +156,7 @@ namespace Terminal.Gui { /// . /// /// Must be configured before showing the dialog. - public FileDialogTreeRootGetter TreeRootGetter { get; set; } = DefaultTreeRootGetter; + public FileDialogTreeRootGetter TreeRootGetter { get; set; } /// /// Gets or sets whether to use advanced unicode characters which might not be installed @@ -167,7 +168,7 @@ namespace Terminal.Gui { /// User defined delegate for picking which character(s)/unicode /// symbol(s) to use as an 'icon' for files/folders. /// - public Func IconGetter { get; set; } + public Func IconGetter { get; set; } /// /// Gets or sets the format to use for date/times in the Modified column. @@ -179,9 +180,17 @@ namespace Terminal.Gui { /// /// Creates a new instance of the class. /// - public FileDialogStyle () + public FileDialogStyle (IFileSystem fileSystem) { + _fileSystem = fileSystem; IconGetter = DefaultIconGetter; + TreeRootGetter = DefaultTreeRootGetter; + + if(NerdFonts.Enable) + { + UseNerdForIcons(); + } + DateFormat = CultureInfo.CurrentCulture.DateTimeFormat.SortableDateTimePattern; ColorSchemeDirectory = new ColorScheme { @@ -210,12 +219,24 @@ namespace Terminal.Gui { Focus = Application.Driver.MakeAttribute (Color.Black, Color.White), HotFocus = Application.Driver.MakeAttribute (Color.Black, Color.White), }; - } - private string DefaultIconGetter (IFileSystemInfo arg) + /// + /// Changes to serve diverse icon set using + /// the Nerd fonts. This option requires users to have specific font(s) + /// installed. + /// + public void UseNerdForIcons () { - if (arg is IDirectoryInfo) { + var nerd = new NerdFonts(); + IconGetter = nerd.GetNerdIcon; + } + + private string DefaultIconGetter (FileDialogIconGetterArgs args) + { + var file = args.File; + + if (file is IDirectoryInfo) { return UseUnicodeCharacters ? "\ua909 " : "\\"; } @@ -223,12 +244,14 @@ namespace Terminal.Gui { } - private static IEnumerable DefaultTreeRootGetter () + private IEnumerable DefaultTreeRootGetter () { var roots = new List (); try { foreach (var d in Environment.GetLogicalDrives ()) { - roots.Add (new FileDialogRootTreeNode (d, new DirectoryInfo (d))); + + + roots.Add (new FileDialogRootTreeNode (d, _fileSystem.DirectoryInfo.New(d))); } } catch (Exception) { @@ -246,7 +269,8 @@ namespace Terminal.Gui { roots.Add (new FileDialogRootTreeNode ( special.ToString (), - new DirectoryInfo (Environment.GetFolderPath (special)))); + _fileSystem.DirectoryInfo.New(Environment.GetFolderPath (special)) + )); } } catch (Exception) { // Special file exists but contents are unreadable (permissions?) diff --git a/Terminal.Gui/FileServices/FileDialogTreeBuilder.cs b/Terminal.Gui/FileServices/FileDialogTreeBuilder.cs index 462a9284d..27906e0db 100644 --- a/Terminal.Gui/FileServices/FileDialogTreeBuilder.cs +++ b/Terminal.Gui/FileServices/FileDialogTreeBuilder.cs @@ -1,11 +1,19 @@ using System; using System.Collections.Generic; using System.IO; +using System.IO.Abstractions; using System.Linq; namespace Terminal.Gui { class FileDialogTreeBuilder : ITreeBuilder { + readonly FileDialog _dlg; + + public FileDialogTreeBuilder(FileDialog dlg) + { + _dlg = dlg; + } + public bool SupportsCanExpand => true; public bool CanExpand (object toExpand) @@ -18,18 +26,40 @@ namespace Terminal.Gui { return this.TryGetDirectories (NodeToDirectory (forObject)); } - internal static DirectoryInfo NodeToDirectory (object toExpand) + internal static IDirectoryInfo NodeToDirectory (object toExpand) { - return toExpand is FileDialogRootTreeNode f ? f.Path : (DirectoryInfo)toExpand; + return toExpand is FileDialogRootTreeNode f ? f.Path : (IDirectoryInfo)toExpand; } - private IEnumerable TryGetDirectories (DirectoryInfo directoryInfo) + internal string AspectGetter(object o) + { + string icon; + string name; + + if(o is FileDialogRootTreeNode r) + { + icon = _dlg.Style.IconGetter.Invoke( + new FileDialogIconGetterArgs(_dlg, r.Path, FileDialogIconGetterContext.Tree)); + name = r.DisplayName; + } + else + { + var dir = (IDirectoryInfo)o; + icon = _dlg.Style.IconGetter.Invoke( + new FileDialogIconGetterArgs(_dlg, dir, FileDialogIconGetterContext.Tree)); + name = dir.Name; + } + + return icon + name; + } + + private IEnumerable TryGetDirectories (IDirectoryInfo directoryInfo) { try { return directoryInfo.EnumerateDirectories (); } catch (Exception) { - return Enumerable.Empty (); + return Enumerable.Empty (); } } diff --git a/Terminal.Gui/Views/FileDialog.cd b/Terminal.Gui/Views/FileDialog.cd index 2b42f6c71..a8174bf7e 100644 --- a/Terminal.Gui/Views/FileDialog.cd +++ b/Terminal.Gui/Views/FileDialog.cd @@ -8,19 +8,19 @@ - - - Windows\FileDialog.cs - - Windows\FileDialog.cs + + + Views\FileDialog.cs + + - goYYDAEnEDIZgHMByFAikQDFSIUQpUDABoZIFRSQwgQ= + g4YYDAEXEDKZgHMFyFAikQCFSKUQhRDABqJIlBSAwgw= Views\FileDialog.cs @@ -75,7 +75,7 @@ - + AAAAEAAAAAAAAAIEAAAAAAAAAAAAAAAAAAAAAAAAAAA= FileServices\FileDialogRootTreeNode.cs @@ -84,7 +84,7 @@ - AABAABAAAAAAAAAAAAAEQAAAAAAAQAAAAgAAAAAAAAI= + AABAABAAAAAAAAIAAAAEQAAAAAAAQAAAAgAAAAAAAAI= FileServices\FileDialogState.cs @@ -94,14 +94,14 @@ - GgBIAAFEAAAAuAAAAAAEEACABAACKRkAAAEYACCAAAA= + GgBIAAFEAAAAuAAAAgAEEASABQACKRkAAAEYACCAAAA= FileServices\FileDialogStyle.cs - EAAAAAAAAAAAAAAAQAAAAAAAAAAAQAAAAAAAAAQACAA= + EAAACAAAAAAAAAAAQAAAAAQAAAAAQAAAAAAAAAQACAA= FileServices\FileDialogTreeBuilder.cs @@ -119,10 +119,38 @@ - ABAIQAIIIAAAAAACQAAAAIQAAAQAAIAAAQABAAAYAAI= + ABAIQAIIIAAAAAACQAAAAIQAAAQAAIAAAQAAAAAIAAI= FileServices\FileSystemInfoStats.cs + + + + + + + AIACAAABQAAAAAAAAAAAAAAAIACAAAAAAAIAAAQAAAA= + Views\NerdFonts.cs + + + + + + AAAAAAAAAgAAAAAAAAAQAAAAAAAEAAAAAAAAAAAAAAA= + FileServices\FileDialogIconGetterArgs.cs + + + + + + + + + AQAAAAAAIAACAEAACAAAAAACAAAEAAAEAAAAgAgBBAA= + Views\FileDialogTableSource.cs + + + @@ -151,8 +179,15 @@ Views\OpenDialog.cs + + + + AAAAAAAAAACAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAA= + FileServices\FileDialogIconGetterContext.cs + + - + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAA= FileServices\FileDialogRootTreeNode.cs diff --git a/Terminal.Gui/Views/FileDialog.cs b/Terminal.Gui/Views/FileDialog.cs index cb980e3fa..6545d360d 100644 --- a/Terminal.Gui/Views/FileDialog.cs +++ b/Terminal.Gui/Views/FileDialog.cs @@ -12,7 +12,6 @@ using Terminal.Gui.Resources; using static Terminal.Gui.ConfigurationManager; namespace Terminal.Gui { - /// /// Modal dialog for selecting files/directories. Has auto-complete and expandable /// navigation pane (Recent, Root drives etc). @@ -24,7 +23,7 @@ namespace Terminal.Gui { /// be made before the is loaded and shown to the user for the /// first time. /// - public FileDialogStyle Style { get; } = new FileDialogStyle (); + public FileDialogStyle Style { get; } /// /// The maximum number of results that will be collected @@ -138,6 +137,8 @@ namespace Terminal.Gui { public FileDialog (IFileSystem fileSystem) { this.fileSystem = fileSystem; + Style = new FileDialogStyle (fileSystem); + this.btnOk = new Button (Style.OkButtonText) { Y = Pos.AnchorEnd (1), X = Pos.Function (() => @@ -259,8 +260,9 @@ namespace Terminal.Gui { Height = Dim.Fill (), }; - this.treeView.TreeBuilder = new FileDialogTreeBuilder (); - this.treeView.AspectGetter = (m) => m is IDirectoryInfo d ? d.Name : m.ToString (); + var fileDialogTreeBuilder = new FileDialogTreeBuilder (this); + this.treeView.TreeBuilder = fileDialogTreeBuilder; + this.treeView.AspectGetter = fileDialogTreeBuilder.AspectGetter; this.Style.TreeStyle = treeView.Style; this.treeView.SelectionChanged += this.TreeView_SelectionChanged; @@ -1139,7 +1141,7 @@ namespace Terminal.Gui { if (this.State == null) { return; } - this.tableView.Table = new FileDialogTableSource (this.State, this.Style, currentSortColumn, currentSortIsAsc); + this.tableView.Table = new FileDialogTableSource (this, this.State, this.Style, currentSortColumn, currentSortIsAsc); this.ApplySort (); this.tableView.Update (); @@ -1267,7 +1269,7 @@ namespace Terminal.Gui { { this.GetProposedNewSortOrder (clickedCol, out var isAsc); this.SortColumn (clickedCol, isAsc); - this.tableView.Table = new FileDialogTableSource (State, Style, currentSortColumn, currentSortIsAsc); + this.tableView.Table = new FileDialogTableSource (this, State, Style, currentSortColumn, currentSortIsAsc); } internal void SortColumn (int col, bool isAsc) diff --git a/Terminal.Gui/Views/FileDialogTableSource.cs b/Terminal.Gui/Views/FileDialogTableSource.cs index 24a7fcf1d..596f32614 100644 --- a/Terminal.Gui/Views/FileDialogTableSource.cs +++ b/Terminal.Gui/Views/FileDialogTableSource.cs @@ -6,13 +6,15 @@ namespace Terminal.Gui { readonly FileDialogStyle style; readonly int currentSortColumn; readonly bool currentSortIsAsc; + readonly FileDialog dlg; readonly FileDialogState state; - public FileDialogTableSource (FileDialogState state, FileDialogStyle style, int currentSortColumn, bool currentSortIsAsc) + public FileDialogTableSource (FileDialog dlg, FileDialogState state, FileDialogStyle style, int currentSortColumn, bool currentSortIsAsc) { this.style = style; this.currentSortColumn = currentSortColumn; this.currentSortIsAsc = currentSortIsAsc; + this.dlg = dlg; this.state = state; } @@ -22,7 +24,8 @@ namespace Terminal.Gui { { switch (col) { case 0: - var icon = stats.IsParent ? null : style.IconGetter?.Invoke (stats.FileSystemInfo); + var icon = stats.IsParent ? null : style.IconGetter?.Invoke ( + new FileDialogIconGetterArgs(dlg,stats.FileSystemInfo, FileDialogIconGetterContext.Table)); return icon + (stats?.Name ?? string.Empty); case 1: return stats?.HumanReadableLength ?? string.Empty; diff --git a/Terminal.Gui/Views/NerdFonts.cs b/Terminal.Gui/Views/NerdFonts.cs new file mode 100644 index 000000000..89fe0c6ef --- /dev/null +++ b/Terminal.Gui/Views/NerdFonts.cs @@ -0,0 +1,790 @@ +// This code is adapted from https://github.com/devblackops/Terminal-Icons (which also uses the MIT license). +// Nerd fonts can be installed by following the instructions on the Nerd Fonts repository: https://github.com/ryanoasis/nerd-fonts + +using System.Collections.Generic; +using System.IO.Abstractions; +using static Terminal.Gui.ConfigurationManager; + +namespace Terminal.Gui { + internal class NerdFonts { + + /// + /// If , enables the use of Nerd unicode symbols. + /// This requires specific font(s) to be installed on the users machine + /// to work correctly. Defaults to . + /// + [SerializableConfigurationProperty (Scope = typeof (ThemeScope))] + public static bool Enable { get; set; } = false; + + public string GetNerdIcon(FileDialogIconGetterArgs args) + { + return GetNerdIconChar(args) + " "; + } + + private char GetNerdIconChar(FileDialogIconGetterArgs args) + { + var file = args.File; + var path = args.FileDialog.Path; + + if(FilenameToIcon.ContainsKey(file.Name)) + { + return Glyphs[FilenameToIcon[file.Name]]; + } + + if(ExtensionToIcon.ContainsKey(file.Extension)) + { + return Glyphs[ExtensionToIcon[file.Extension]]; + } + + if(file is IDirectoryInfo d) + { + if(!string.IsNullOrWhiteSpace(path) && + path.Contains(d.FullName) && + args.Context == FileDialogIconGetterContext.Tree) + { + return _nf_cod_folder_opened; + } + return _nf_cod_folder; + } + + return _nf_cod_file; + } + char _nf_cod_folder = ''; + char _nf_cod_folder_opened = ''; + char _nf_cod_file = ''; + + /// + /// All nerd glyphs used by Terminal.Gui by name. + /// + public Dictionary Glyphs {get;set;} = new Dictionary{ + {"nf-cod-package", ''}, + {"nf-cod-preview", ''}, + {"nf-custom-folder_config", ''}, + {"nf-custom-folder_git", ''}, + {"nf-custom-folder_git_branch", ''}, + {"nf-custom-folder_github", ''}, + {"nf-custom-folder_npm", ''}, + {"nf-dev-aws", ''}, + {"nf-dev-docker", ''}, + {"nf-dev-html5_multimedia", ''}, + {"nf-fa-font", ''}, + {"nf-fa-font_awesome", ''}, + {"nf-fa-fonticons", ''}, + {"nf-fa-github_alt", ''}, + {"nf-fa-users", ''}, + {"nf-fa-windows", ''}, + {"nf-mdi-apps", ''}, + {"nf-mdi-azure", 'ﴃ'}, + {"nf-mdi-cached", ''}, + {"nf-mdi-contacts", '﯉'}, + {"nf-mdi-desktop_classic", 'ﲾ'}, + {"nf-mdi-folder_download", ''}, + {"nf-mdi-folder_image", ''}, + {"nf-mdi-folder_star", 'ﮛ'}, + {"nf-mdi-library_music", ''}, + {"nf-mdi-movie", ''}, + {"nf-mdi-movie_roll", 'ﳜ'}, + {"nf-mdi-onedrive", ''}, + {"nf-mdi-ship_wheel", 'ﴱ'}, + {"nf-mdi-test_tube", 'ﭧ'}, + {"nf-mdi-timer", '祥'}, + {"nf-mdi-timer_10", '福'}, + {"nf-mdi-timer_3", '靖'}, + {"nf-mdi-timer_off", '精'}, + {"nf-mdi-timer_sand", '羽'}, + {"nf-mdi-timer_sand_empty", 'ﮫ'}, + {"nf-mdi-timer_sand_full", 'ﲊ'}, + {"nf-mdi-umbraco", '煮'}, + {"nf-oct-file_binary", ''}, + {"nf-oct-file_symlink_directory", ''}, + {"nf-oct-repo", ''}, + {"nf-oct-repo_clone", ''}, + {"nf-oct-repo_force_push", ''}, + {"nf-oct-repo_forked", ''}, + {"nf-oct-repo_pull", ''}, + {"nf-oct-repo_push", ''}, + {"nf-oct-terminal", ''}, + {"nf-seti-config", ''}, + {"nf-seti-project", ''}, + {"nf-custom-elixir", ''}, + {"nf-custom-elm", ''}, + {"nf-custom-msdos", ''}, + {"nf-custom-puppet", ''}, + {"nf-custom-vim", ''}, + {"nf-dev-apple", ''}, + {"nf-dev-bitbucket", ''}, + {"nf-dev-bower", ''}, + {"nf-dev-clojure", ''}, + {"nf-dev-clojure_alt", ''}, + {"nf-dev-code_badge", ''}, + {"nf-dev-css3", ''}, + {"nf-dev-css3_full", ''}, + {"nf-dev-dart", ''}, + {"nf-dev-database", ''}, + {"nf-dev-erlang", ''}, + {"nf-dev-firebase", ''}, + {"nf-dev-fsharp", ''}, + {"nf-dev-git", ''}, + {"nf-dev-git_branch", ''}, + {"nf-dev-git_commit", ''}, + {"nf-dev-git_compare", ''}, + {"nf-dev-git_merge", ''}, + {"nf-dev-git_pull_request", ''}, + {"nf-dev-github", ''}, + {"nf-dev-github_alt", ''}, + {"nf-dev-github_badge", ''}, + {"nf-dev-github_full", ''}, + {"nf-dev-go", ''}, + {"nf-dev-google_cloud_platform", ''}, + {"nf-dev-google_drive", ''}, + {"nf-dev-groovy", ''}, + {"nf-dev-gulp", ''}, + {"nf-dev-haskell", ''}, + {"nf-dev-javascript", ''}, + {"nf-dev-javascript_badge", ''}, + {"nf-dev-javascript_shield", ''}, + {"nf-dev-jenkins", ''}, + {"nf-dev-less", ''}, + {"nf-dev-markdown", ''}, + {"nf-dev-nodejs_small", ''}, + {"nf-dev-npm", ''}, + {"nf-dev-perl", ''}, + {"nf-dev-php", ''}, + {"nf-dev-python", ''}, + {"nf-dev-react", ''}, + {"nf-dev-rust", ''}, + {"nf-dev-sass", ''}, + {"nf-dev-sublime", ''}, + {"nf-dev-travis", ''}, + {"nf-dev-visualstudio", ''}, + {"nf-fa-archive", ''}, + {"nf-fa-calendar", ''}, + {"nf-fa-calendar_check_o", ''}, + {"nf-fa-calendar_minus_o", ''}, + {"nf-fa-calendar_o", ''}, + {"nf-fa-calendar_plus_o", ''}, + {"nf-fa-calendar_times_o", ''}, + {"nf-fa-certificate", ''}, + {"nf-fa-eye", ''}, + {"nf-fa-eye_slash", ''}, + {"nf-fa-eyedropper", ''}, + {"nf-fa-file_audio_o", ''}, + {"nf-fa-file_image_o", ''}, + {"nf-fa-file_o", ''}, + {"nf-fa-file_video_o", ''}, + {"nf-fa-gear", ''}, + {"nf-fa-gears", ''}, + {"nf-fa-gitlab", ''}, + {"nf-fa-handshake_o", ''}, + {"nf-fa-key", ''}, + {"nf-fa-keyboard_o", ''}, + {"nf-fa-list", ''}, + {"nf-fa-list_alt", ''}, + {"nf-fa-list_ol", ''}, + {"nf-fa-list_ul", ''}, + {"nf-fa-lock", ''}, + {"nf-fae-checklist_o", ''}, + {"nf-fae-disco", ''}, + {"nf-fae-java", ''}, + {"nf-mdi-application", 'ﬓ'}, + {"nf-mdi-certificate", ''}, + {"nf-mdi-console_line", 'ﲵ'}, + {"nf-mdi-elephant", 'ﳄ'}, + {"nf-mdi-file_document", ''}, + {"nf-mdi-file_document_box", ''}, + {"nf-mdi-file_excel", ''}, + {"nf-mdi-file_excel_box", ''}, + {"nf-mdi-file_pdf", ''}, + {"nf-mdi-file_pdf_box", ''}, + {"nf-mdi-file_powerpoint", ''}, + {"nf-mdi-file_powerpoint_box", ''}, + {"nf-mdi-file_word", ''}, + {"nf-mdi-file_word_box", ''}, + {"nf-mdi-file_xml", ''}, + {"nf-mdi-format_align_left", ''}, + {"nf-mdi-harddisk", ''}, + {"nf-mdi-help_box", 'ﲉ'}, + {"nf-mdi-language_c", 'ﭰ'}, + {"nf-mdi-language_cpp", 'ﭱ'}, + {"nf-mdi-language_csharp", ''}, + {"nf-mdi-language_css3", ''}, + {"nf-mdi-language_r", 'ﳒ'}, + {"nf-mdi-library_books", ''}, + {"nf-mdi-notebook", 'ﴬ'}, + {"nf-mdi-package_variant", ''}, + {"nf-mdi-package_variant_closed", ''}, + {"nf-mdi-svg", 'ﰟ'}, + {"nf-mdi-visualstudio", '﬏'}, + {"nf-mdi-vuejs", '﵂'}, + {"nf-mdi-xaml", 'ﭲ'}, + {"nf-oct-file_zip", ''}, + {"nf-oct-person", ''}, + {"nf-oct-ruby", ''}, + {"nf-seti-favicon", ''}, + {"nf-seti-grunt", ''}, + {"nf-seti-html", ''}, + {"nf-seti-json", ''}, + {"nf-seti-julia", ''}, + {"nf-seti-lua", ''}, + {"nf-seti-mustache", ''}, + {"nf-seti-typescript", ''}, + + }; + + /// + /// Mapping of file name to name. + /// + public Dictionary FilenameToIcon {get;set;} = new Dictionary () + { + {"docs","nf-oct-repo"}, + {"documents","nf-oct-repo"}, + {"desktop","nf-mdi-desktop_classic"}, + {"benchmark","nf-mdi-timer"}, + {"demo","nf-cod-preview"}, + {"samples","nf-cod-preview"}, + {"contacts","nf-mdi-contacts"}, + {"apps","nf-mdi-apps"}, + {"applications","nf-mdi-apps"}, + {"artifacts","nf-cod-package"}, + {"shortcuts","nf-oct-file_symlink_directory"}, + {"links","nf-oct-file_symlink_directory"}, + {"fonts","nf-fa-font"}, + {"images","nf-mdi-folder_image"}, + {"photos","nf-mdi-folder_image"}, + {"pictures","nf-mdi-folder_image"}, + {"videos","nf-mdi-movie"}, + {"movies","nf-mdi-movie"}, + {"media","nf-dev-html5_multimedia"}, + {"music","nf-mdi-library_music"}, + {"songs","nf-mdi-library_music"}, + {"onedrive","nf-mdi-onedrive"}, + {"downloads","nf-mdi-folder_download"}, + {"src","nf-oct-terminal"}, + {"development","nf-oct-terminal"}, + {"projects","nf-seti-project"}, + {"bin","nf-oct-file_binary"}, + {"tests","nf-mdi-test_tube"}, + {"windows","nf-fa-windows"}, + {"users","nf-fa-users"}, + {"favorites","nf-mdi-folder_star"}, + {".config","nf-seti-config"}, + {".cache","nf-mdi-cached"}, + {".vscode","nf-custom-folder_config"}, + {".vscode-insiders","nf-custom-folder_config"}, + {".git","nf-custom-folder_git"}, + {".github","nf-custom-folder_github"}, + {"github","nf-fa-github_alt"}, + {"node_modules","nf-custom-folder_npm"}, + {".azure","nf-mdi-azure"}, + {".aws","nf-dev-aws"}, + {".kube","nf-mdi-ship_wheel"}, + {".docker","nf-dev-docker"}, + {"umbraco","nf-mdi-umbraco"}, + {".gitattributes", "nf-dev-git"}, + {".gitconfig", "nf-dev-git"}, + {".gitignore", "nf-dev-git"}, + {".gitmodules", "nf-dev-git"}, + {".gitkeep", "nf-dev-git"}, + {"git-history", "nf-dev-git"}, + {"LICENSE", "nf-mdi-certificate"}, + {"CHANGELOG.md", "nf-fae-checklist_o"}, + {"CHANGELOG.txt", "nf-fae-checklist_o"}, + {"CHANGELOG", "nf-fae-checklist_o"}, + {"README.md", "nf-mdi-library_books"}, + {"README.txt", "nf-mdi-library_books"}, + {"README", "nf-mdi-library_books"}, + {".DS_Store", "nf-fa-file_o"}, + {".tsbuildinfo", "nf-seti-json"}, + {".jscsrc", "nf-seti-json"}, + {".jshintrc", "nf-seti-json"}, + {"tsconfig.json", "nf-seti-json"}, + {"tslint.json", "nf-seti-json"}, + {"composer.lock", "nf-seti-json"}, + {".jsbeautifyrc", "nf-seti-json"}, + {".esformatter", "nf-seti-json"}, + {"cdp.pid", "nf-seti-json"}, + {".htaccess", "nf-mdi-file_xml"}, + {".jshintignore", "nf-fa-gear"}, + {".buildignore", "nf-fa-gear"}, + {".mrconfig", "nf-fa-gear"}, + {".yardopts", "nf-fa-gear"}, + {"manifest.mf", "nf-fa-gear"}, + {".clang-format", "nf-fa-gear"}, + {".clang-tidy", "nf-fa-gear"}, + {"favicon.ico", "nf-seti-favicon"}, + {".travis.yml", "nf-dev-travis"}, + {".gitlab-ci.yml", "nf-fa-gitlab"}, + {".jenkinsfile", "nf-dev-jenkins"}, + {"bitbucket-pipelines.yml", "nf-dev-bitbucket"}, + {"bitbucket-pipelines.yaml", "nf-dev-bitbucket"}, + {".azure-pipelines.yml", "nf-mdi-azure"}, + + + // Firebase + {"firebase.json", "nf-dev-firebase"}, + {".firebaserc", "nf-dev-firebase"}, + + // Bower + {".bowerrc", "nf-dev-bower"}, + {"bower.json", "nf-dev-bower"}, + + // Conduct + {"code_of_conduct.md", "nf-fa-handshake_o"}, + {"code_of_conduct.txt", "nf-fa-handshake_o"}, + + // Docker + {"Dockerfile", "nf-dev-docker"}, + {"docker-compose.yml", "nf-dev-docker"}, + {"docker-compose.yaml", "nf-dev-docker"}, + {"docker-compose.dev.yml", "nf-dev-docker"}, + {"docker-compose.local.yml", "nf-dev-docker"}, + {"docker-compose.ci.yml", "nf-dev-docker"}, + {"docker-compose.override.yml", "nf-dev-docker"}, + {"docker-compose.staging.yml", "nf-dev-docker"}, + {"docker-compose.prod.yml", "nf-dev-docker"}, + {"docker-compose.production.yml", "nf-dev-docker"}, + {"docker-compose.test.yml", "nf-dev-docker"}, + + // Vue + {"vue.config.js", "nf-mdi-vuejs"}, + {"vue.config.ts", "nf-mdi-vuejs"}, + + // Gulp + {"gulpfile.js", "nf-dev-gulp"}, + {"gulpfile.ts", "nf-dev-gulp"}, + {"gulpfile.babel.js", "nf-dev-gulp"}, + + // Javascript + {"gruntfile.js", "nf-seti-grunt"}, + + // NodeJS + {"package.json", "nf-dev-nodejs_small"}, + {"package-lock.json", "nf-dev-nodejs_small"}, + {".nvmrc", "nf-dev-nodejs_small"}, + {".esmrc", "nf-dev-nodejs_small"}, + + // NPM + {".nmpignore", "nf-dev-npm"}, + {".npmrc", "nf-dev-npm"}, + + // Authors + {"authors", "nf-oct-person"}, + {"authors.md", "nf-oct-person"}, + {"authors.txt", "nf-oct-person"}, + + // Terraform + {".terraform.lock.hcl", "nf-fa-lock"}, + + // Gradle + {"gradlew", "nf-mdi-elephant"}, + }; + + /// + /// Mapping of file extension to name. + /// + public Dictionary ExtensionToIcon {get;set;} = new Dictionary () + { + + // Archive files + {".7z" , "nf-oct-file_zip"}, + {".bz" , "nf-oct-file_zip"}, + {".tar" , "nf-oct-file_zip"}, + {".zip" , "nf-oct-file_zip"}, + {".gz" , "nf-oct-file_zip"}, + {".xz" , "nf-oct-file_zip"}, + {".br" , "nf-oct-file_zip"}, + {".bzip2" , "nf-oct-file_zip"}, + {".gzip" , "nf-oct-file_zip"}, + {".brotli" , "nf-oct-file_zip"}, + {".rar" , "nf-oct-file_zip"}, + {".tgz" , "nf-oct-file_zip"}, + + // Executable things + {".bat" , "nf-custom-msdos"}, + {".cmd" , "nf-custom-msdos"}, + {".exe" , "nf-mdi-application"}, + {".pl" , "nf-dev-perl"}, + + {".sh" , "nf-oct-terminal"}, + + // App Packages + {".msi" , "nf-mdi-package_variant"}, + {".msix" , "nf-mdi-package_variant"}, + {".msixbundle" , "nf-mdi-package_variant"}, + {".appx" , "nf-mdi-package_variant"}, + {".AppxBundle" , "nf-mdi-package_variant"}, + {".deb" , "nf-mdi-package_variant"}, + {".rpm" , "nf-mdi-package_variant"}, + + // PowerShell + {".ps1" , "nf-mdi-console_line"}, + {".psm1" , "nf-mdi-console_line"}, + {".psd1" , "nf-mdi-console_line"}, + {".ps1xml" , "nf-mdi-console_line"}, + {".psc1" , "nf-mdi-console_line"}, + {".pssc" , "nf-mdi-console_line"}, + + // Javascript + {".js" , "nf-dev-javascript"}, + {".esx" , "nf-dev-javascript"}, + {".mjs" , "nf-dev-javascript"}, + + // Java + {".java" , "nf-fae-java"}, + {".jar" , "nf-fae-java"}, + + {".gradle" , "nf-mdi-elephant"}, + + // Python + {".py" , "nf-dev-python"}, + {".ipynb" , "nf-mdi-notebook"}, + + // React + {".jsx" , "nf-dev-react"}, + {".tsx" , "nf-dev-react"}, + + // Typescript + {".ts" , "nf-seti-typescript"}, + + // Not-executable code files + {".dll" , "nf-fa-archive"}, + + // Importable Data files + {".clixml" , "nf-dev-code_badge"}, + {".csv" , "nf-mdi-file_excel"}, + {".tsv" , "nf-mdi-file_excel"}, + + // Settings + {".ini" , "nf-fa-gear"}, + {".dlc" , "nf-fa-gear"}, + {".config" , "nf-fa-gear"}, + {".conf" , "nf-fa-gear"}, + {".properties" , "nf-fa-gear"}, + {".prop" , "nf-fa-gear"}, + {".settings" , "nf-fa-gear"}, + {".option" , "nf-fa-gear"}, + {".reg" , "nf-fa-gear"}, + {".props" , "nf-fa-gear"}, + {".toml" , "nf-fa-gear"}, + {".prefs" , "nf-fa-gear"}, + {".sln.dotsettings" , "nf-fa-gear"}, + {".sln.dotsettings.user" , "nf-fa-gear"}, + {".cfg" , "nf-fa-gear"}, + + // Source Files + {".c" , "nf-mdi-language_c"}, + {".cpp" , "nf-mdi-language_cpp"}, + {".go" , "nf-dev-go"}, + {".php" , "nf-dev-php"}, + + // Visual Studio + {".csproj" , "nf-dev-visualstudio"}, + {".ruleset" , "nf-dev-visualstudio"}, + {".sln" , "nf-dev-visualstudio"}, + {".slnf" , "nf-dev-visualstudio"}, + {".suo" , "nf-dev-visualstudio"}, + {".vb" , "nf-dev-visualstudio"}, + {".vbs" , "nf-dev-visualstudio"}, + {".vcxitems" , "nf-dev-visualstudio"}, + {".vcxitems.filters" , "nf-dev-visualstudio"}, + {".vcxproj" , "nf-dev-visualstudio"}, + {".vsxproj.filters" , "nf-dev-visualstudio"}, + + // CSharp + {".cs" , "nf-mdi-language_csharp"}, + {".csx" , "nf-mdi-language_csharp"}, + + // Haskell + {".hs" , "nf-dev-haskell"}, + + // XAML + {".xaml" , "nf-mdi-xaml"}, + + // Rust + {".rs" , "nf-dev-rust"}, + + // Database + {".pdb" , "nf-dev-database"}, + {".sql" , "nf-dev-database"}, + {".pks" , "nf-dev-database"}, + {".pkb" , "nf-dev-database"}, + {".accdb" , "nf-dev-database"}, + {".mdb" , "nf-dev-database"}, + {".sqlite" , "nf-dev-database"}, + {".pgsql" , "nf-dev-database"}, + {".postgres" , "nf-dev-database"}, + {".psql" , "nf-dev-database"}, + + // Source Control + {".patch" , "nf-dev-git"}, + + // Project files + {".user" , "nf-mdi-visualstudio"}, + {".code-workspace" , "nf-mdi-visualstudio"}, + + // Text data files + {".log" , "nf-fa-list"}, + {".txt" , "nf-mdi-file_document"}, + + // Subtitle files + {".srt" , "nf-mdi-file_document"}, + {".lrc" , "nf-mdi-file_document"}, + {".ass" , "nf-fa-eye"}, + + // HTML/css + {".html" , "nf-seti-html"}, + {".htm" , "nf-seti-html"}, + {".xhtml" , "nf-seti-html"}, + {".html_vm" , "nf-seti-html"}, + {".asp" , "nf-seti-html"}, + {".css" , "nf-dev-css3"}, + {".sass" , "nf-dev-sass"}, + {".scss" , "nf-dev-sass"}, + {".less" , "nf-dev-less"}, + + // Markdown + {".md" , "nf-dev-markdown"}, + {".markdown" , "nf-dev-markdown"}, + {".rst" , "nf-dev-markdown"}, + + // Handlebars + {".hbs" , "nf-seti-mustache"}, + + // JSON + {".json" , "nf-seti-json"}, + {".tsbuildinfo" , "nf-seti-json"}, + + // YAML + {".yml" , "nf-mdi-format_align_left"}, + {".yaml" , "nf-mdi-format_align_left"}, + + // LUA + {".lua" , "nf-seti-lua"}, + + // Clojure + {".clj" , "nf-dev-clojure"}, + {".cljs" , "nf-dev-clojure"}, + {".cljc" , "nf-dev-clojure"}, + + // Groovy + {".groovy" , "nf-dev-groovy"}, + + // Vue + {".vue" , "nf-mdi-vuejs"}, + + // Dart + {".dart" , "nf-dev-dart"}, + + // Elixir + {".ex" , "nf-custom-elixir"}, + {".exs" , "nf-custom-elixir"}, + {".eex" , "nf-custom-elixir"}, + {".leex" , "nf-custom-elixir"}, + + // Erlang + {".erl" , "nf-dev-erlang"}, + + // Elm + {".elm" , "nf-custom-elm"}, + + // Applescript + {".applescript" , "nf-dev-apple"}, + + // XML + {".xml" , "nf-mdi-file_xml"}, + {".plist" , "nf-mdi-file_xml"}, + {".xsd" , "nf-mdi-file_xml"}, + {".dtd" , "nf-mdi-file_xml"}, + {".xsl" , "nf-mdi-file_xml"}, + {".xslt" , "nf-mdi-file_xml"}, + {".resx" , "nf-mdi-file_xml"}, + {".iml" , "nf-mdi-file_xml"}, + {".xquery" , "nf-mdi-file_xml"}, + {".tmLanguage" , "nf-mdi-file_xml"}, + {".manifest" , "nf-mdi-file_xml"}, + {".project" , "nf-mdi-file_xml"}, + + // Documents + {".chm" , "nf-mdi-help_box"}, + {".pdf" , "nf-mdi-file_pdf"}, + + // Excel + {".xls" , "nf-mdi-file_excel"}, + {".xlsx" , "nf-mdi-file_excel"}, + + // PowerPoint + {".pptx" , "nf-mdi-file_powerpoint"}, + {".ppt" , "nf-mdi-file_powerpoint"}, + {".pptm" , "nf-mdi-file_powerpoint"}, + {".potx" , "nf-mdi-file_powerpoint"}, + {".potm" , "nf-mdi-file_powerpoint"}, + {".ppsx" , "nf-mdi-file_powerpoint"}, + {".ppsm" , "nf-mdi-file_powerpoint"}, + {".pps" , "nf-mdi-file_powerpoint"}, + {".ppam" , "nf-mdi-file_powerpoint"}, + {".ppa" , "nf-mdi-file_powerpoint"}, + + // Word + {".doc" , "nf-mdi-file_word"}, + {".docx" , "nf-mdi-file_word"}, + {".rtf" , "nf-mdi-file_word"}, + + // Audio + {".mp3" , "nf-fa-file_audio_o"}, + {".flac" , "nf-fa-file_audio_o"}, + {".m4a" , "nf-fa-file_audio_o"}, + {".wma" , "nf-fa-file_audio_o"}, + {".aiff" , "nf-fa-file_audio_o"}, + {".wav" , "nf-fa-file_audio_o"}, + {".aac" , "nf-fa-file_audio_o"}, + {".opus" , "nf-fa-file_audio_o"}, + + // Images + {".png" , "nf-fa-file_image_o"}, + {".jpeg" , "nf-fa-file_image_o"}, + {".jpg" , "nf-fa-file_image_o"}, + {".gif" , "nf-fa-file_image_o"}, + {".ico" , "nf-fa-file_image_o"}, + {".tif" , "nf-fa-file_image_o"}, + {".tiff" , "nf-fa-file_image_o"}, + {".psd" , "nf-fa-file_image_o"}, + {".psb" , "nf-fa-file_image_o"}, + {".ami" , "nf-fa-file_image_o"}, + {".apx" , "nf-fa-file_image_o"}, + {".bmp" , "nf-fa-file_image_o"}, + {".bpg" , "nf-fa-file_image_o"}, + {".brk" , "nf-fa-file_image_o"}, + {".cur" , "nf-fa-file_image_o"}, + {".dds" , "nf-fa-file_image_o"}, + {".dng" , "nf-fa-file_image_o"}, + {".eps" , "nf-fa-file_image_o"}, + {".exr" , "nf-fa-file_image_o"}, + {".fpx" , "nf-fa-file_image_o"}, + {".gbr" , "nf-fa-file_image_o"}, + {".jbig2" , "nf-fa-file_image_o"}, + {".jb2" , "nf-fa-file_image_o"}, + {".jng" , "nf-fa-file_image_o"}, + {".jxr" , "nf-fa-file_image_o"}, + {".pbm" , "nf-fa-file_image_o"}, + {".pgf" , "nf-fa-file_image_o"}, + {".pic" , "nf-fa-file_image_o"}, + {".raw" , "nf-fa-file_image_o"}, + {".webp" , "nf-fa-file_image_o"}, + {".svg" , "nf-mdi-svg"}, + + // Video + {".webm" , "nf-fa-file_video_o"}, + {".mkv" , "nf-fa-file_video_o"}, + {".flv" , "nf-fa-file_video_o"}, + {".vob" , "nf-fa-file_video_o"}, + {".ogv" , "nf-fa-file_video_o"}, + {".ogg" , "nf-fa-file_video_o"}, + {".gifv" , "nf-fa-file_video_o"}, + {".avi" , "nf-fa-file_video_o"}, + {".mov" , "nf-fa-file_video_o"}, + {".qt" , "nf-fa-file_video_o"}, + {".wmv" , "nf-fa-file_video_o"}, + {".yuv" , "nf-fa-file_video_o"}, + {".rm" , "nf-fa-file_video_o"}, + {".rmvb" , "nf-fa-file_video_o"}, + {".mp4" , "nf-fa-file_video_o"}, + {".mpg" , "nf-fa-file_video_o"}, + {".mp2" , "nf-fa-file_video_o"}, + {".mpeg" , "nf-fa-file_video_o"}, + {".mpe" , "nf-fa-file_video_o"}, + {".mpv" , "nf-fa-file_video_o"}, + {".m2v" , "nf-fa-file_video_o"}, + + // Email + {".ics" , "nf-fa-calendar"}, + + // Certificates + {".cer" , "nf-fa-certificate"}, + {".cert" , "nf-fa-certificate"}, + {".crt" , "nf-fa-certificate"}, + {".pfx" , "nf-fa-certificate"}, + + // Keys + {".pem" , "nf-fa-key"}, + {".pub" , "nf-fa-key"}, + {".key" , "nf-fa-key"}, + {".asc" , "nf-fa-key"}, + {".gpg" , "nf-fa-key"}, + + // Fonts + {".woff" , "nf-fa-font"}, + {".woff2" , "nf-fa-font"}, + {".ttf" , "nf-fa-font"}, + {".eot" , "nf-fa-font"}, + {".suit" , "nf-fa-font"}, + {".otf" , "nf-fa-font"}, + {".bmap" , "nf-fa-font"}, + {".fnt" , "nf-fa-font"}, + {".odttf" , "nf-fa-font"}, + {".ttc" , "nf-fa-font"}, + {".font" , "nf-fa-font"}, + {".fonts" , "nf-fa-font"}, + {".sui" , "nf-fa-font"}, + {".ntf" , "nf-fa-font"}, + {".mrg" , "nf-fa-font"}, + + // Ruby + {".rb" , "nf-oct-ruby"}, + {".erb" , "nf-oct-ruby"}, + {".gemfile" , "nf-oct-ruby"}, + {"rakefile" , "nf-oct-ruby"}, + + // FSharp + {".fs" , "nf-dev-fsharp"}, + {".fsx" , "nf-dev-fsharp"}, + {".fsi" , "nf-dev-fsharp"}, + {".fsproj" , "nf-dev-fsharp"}, + + // Docker + {".dockerignore" , "nf-dev-docker"}, + {".dockerfile" , "nf-dev-docker"}, + + // VSCode + {".vscodeignore" , "nf-fa-gear"}, + {".vsixmanifest" , "nf-fa-gear"}, + {".vsix" , "nf-fa-gear"}, + {".code-workplace" , "nf-fa-gear"}, + + // Sublime + {".sublime-project" , "nf-dev-sublime"}, + {".sublime-workspace" , "nf-dev-sublime"}, + + {".lock" , "nf-fa-lock"}, + + // Terraform + {".tf" , "nf-dev-code_badge"}, + {".tfvars" , "nf-dev-code_badge"}, + {".tf.json" , "nf-dev-code_badge"}, + {".tfvars.json" , "nf-dev-code_badge"}, + {".auto.tfvars" , "nf-dev-code_badge"}, + {".auto.tfvars.json" , "nf-dev-code_badge"}, + + // Disk Image + {".vmdk" , "nf-mdi-harddisk"}, + {".vhd" , "nf-mdi-harddisk"}, + {".vhdx" , "nf-mdi-harddisk"}, + {".img" , "nf-fae-disco"}, + {".iso" , "nf-fae-disco"}, + + // R language + {".R" , "nf-mdi-language_r"}, + {".Rmd" , "nf-mdi-language_r"}, + {".Rproj" , "nf-mdi-language_r"}, + + // Julia language + {".jl" , "nf-seti-julia"}, + + // Vim + {".vim" , "nf-custom-vim"}, + + // Puppet + {".pp" , "nf-custom-puppet"}, + {".epp" , "nf-custom-puppet"}, + }; + } +} \ No newline at end of file diff --git a/UICatalog/Scenarios/FileDialogExamples.cs b/UICatalog/Scenarios/FileDialogExamples.cs index 0f44f9a63..ff978715f 100644 --- a/UICatalog/Scenarios/FileDialogExamples.cs +++ b/UICatalog/Scenarios/FileDialogExamples.cs @@ -13,7 +13,6 @@ namespace UICatalog.Scenarios { [ScenarioCategory ("Files and IO")] public class FileDialogExamples : Scenario { private CheckBox cbMustExist; - private CheckBox cbUnicode; private CheckBox cbUseColors; private CheckBox cbCaseSensitive; private CheckBox cbAllowMultipleSelection; @@ -23,6 +22,7 @@ namespace UICatalog.Scenarios { private RadioGroup rgCaption; private RadioGroup rgOpenMode; + private RadioGroup rgIcons; private RadioGroup rgAllowedTypes; public override void Setup () @@ -33,9 +33,6 @@ namespace UICatalog.Scenarios { cbMustExist = new CheckBox ("Must Exist") { Checked = true, Y = y++, X = x }; Win.Add (cbMustExist); - cbUnicode = new CheckBox ("UseUnicode") { Checked = FileDialogStyle.DefaultUseUnicodeCharacters, Y = y++, X = x }; - Win.Add (cbUnicode); - cbUseColors = new CheckBox ("Use Colors") { Checked = FileDialogStyle.DefaultUseColors, Y = y++, X = x }; Win.Add (cbUseColors); @@ -69,7 +66,7 @@ namespace UICatalog.Scenarios { Win.Add (rgCaption); y = 0; - x = 37; + x = 34; Win.Add (new LineView (Orientation.Vertical) { X = x++, @@ -82,6 +79,23 @@ namespace UICatalog.Scenarios { rgOpenMode.RadioLabels = new NStack.ustring [] { "File", "Directory", "Mixed" }; Win.Add (rgOpenMode); + y = 0; + x = 48; + + Win.Add (new LineView (Orientation.Vertical) { + X = x++, + Y = 1, + Height = 4 + }); + Win.Add (new Label ("Icons") { X = x++, Y = y++ }); + + rgIcons = new RadioGroup { X = x, Y = y }; + rgIcons.RadioLabels = new NStack.ustring [] { "None", "Unicode", "Nerd*" }; + Win.Add (rgIcons); + + Win.Add(new Label("* Requires installing Nerd fonts"){Y = Pos.AnchorEnd(2)}); + Win.Add(new Label(" (see: https://github.com/devblackops/Terminal-Icons)"){Y = Pos.AnchorEnd(1)}); + y = 5; x = 24; @@ -137,7 +151,14 @@ namespace UICatalog.Scenarios { fd.FilesSelected += ConfirmOverwrite; } - fd.Style.UseUnicodeCharacters = cbUnicode.Checked ?? false; + if(rgIcons.SelectedItem == 1) + { + fd.Style.UseUnicodeCharacters = true; + } + else if(rgIcons.SelectedItem == 2) + { + fd.Style.UseNerdForIcons(); + } if (cbCaseSensitive.Checked ?? false) { @@ -149,10 +170,12 @@ namespace UICatalog.Scenarios { fd.Style.TreeStyle.ShowBranchLines = cbShowTreeBranchLines.Checked ?? false; fd.Style.TableStyle.AlwaysShowHeaders = cbAlwaysTableShowHeaders.Checked ?? false; + var dirInfoFactory = new FileSystem().DirectoryInfo; + if (cbDrivesOnlyInTree.Checked ?? false) { fd.Style.TreeRootGetter = () => { return System.Environment.GetLogicalDrives () - .Select (d => new FileDialogRootTreeNode (d, new DirectoryInfo (d))); + .Select (d => new FileDialogRootTreeNode (d, dirInfoFactory.New(d))); }; } diff --git a/UnitTests/FileServices/NerdFontsTests.cs b/UnitTests/FileServices/NerdFontsTests.cs new file mode 100644 index 000000000..37db65fa6 --- /dev/null +++ b/UnitTests/FileServices/NerdFontsTests.cs @@ -0,0 +1,37 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.IO; +using System.IO.Abstractions.TestingHelpers; +using System.Linq; +using Terminal.Gui; +using Xunit; +using Xunit.Abstractions; + +namespace Terminal.Gui.FileServicesTests { + + public class NerdFontTests + { + [Fact] + public void TestAllFilenamesMapToKnownGlyphs() + { + var f = new NerdFonts(); + foreach(var k in f.FilenameToIcon) + { + Assert.Contains(k.Value, f.Glyphs.Keys); + } + } + + + [Fact] + public void TestAllExtensionsMapToKnownGlyphs() + { + var f = new NerdFonts(); + foreach(var k in f.ExtensionToIcon) + { + Assert.Contains(k.Value, f.Glyphs.Keys); + } + } + } + +} \ No newline at end of file