protected string ReadFile( string filePath, string basePath, Encoding encoding, SearchContext context, string indent = null) { try { using (var stream = new FileStream(filePath, FileMode.Open, FileAccess.Read)) using (var reader = new StreamReader(stream, encoding, detectEncodingFromByteOrderMarks: true)) { return(reader.ReadToEnd()); } } catch (Exception ex) when(ex is IOException || ex is UnauthorizedAccessException) { EndProgress(context); LogHelpers.WriteFileError(ex, filePath, basePath, relativePath: Options.DisplayRelativePath, indent: indent); return(null); } }
protected override void WriteSummary(SearchTelemetry telemetry, Verbosity verbosity) { base.WriteSummary(telemetry, verbosity); ConsoleColors colors = (Options.DryRun) ? Colors.Message_DryRun : Colors.Message_Change; if (telemetry.ProcessedFileCount > 0) { LogHelpers.WriteCount("Moved files", telemetry.ProcessedFileCount, colors, verbosity); } if (telemetry.ProcessedDirectoryCount > 0) { if (telemetry.ProcessedFileCount > 0) { Logger.Write(" ", verbosity); } LogHelpers.WriteCount("Moved directories", telemetry.ProcessedDirectoryCount, colors, verbosity); } Logger.WriteLine(verbosity); }
protected override void ExecuteMatchCore( FileMatch fileMatch, SearchContext context, string?baseDirectoryPath, ColumnWidths?columnWidths) { string indent = GetPathIndent(baseDirectoryPath); List <ReplaceItem> replaceItems = ReplaceHelpers.GetReplaceItems(fileMatch.NameMatch !, Options.ReplaceOptions, NameFilter !.Predicate, context.CancellationToken); string path = fileMatch.Path; string newPath = ReplaceHelpers.GetNewPath(fileMatch, replaceItems); bool changed = !string.Equals(path, newPath, StringComparison.Ordinal); if (!Options.OmitPath && changed) { LogHelpers.WritePath( fileMatch, replaceItems, baseDirectoryPath, relativePath: Options.DisplayRelativePath, colors: Colors.Matched_Path, matchColors: (Options.HighlightMatch) ? Colors.Match : default,
protected override void ExecuteResult( FileSystemFinderResult result, SearchContext context, string baseDirectoryPath, ColumnWidths columnWidths) { string indent = GetPathIndent(baseDirectoryPath); List <ReplaceItem> replaceItems = GetReplaceItems(result, context.CancellationToken); string path = result.Path; string newPath = GetNewPath(result, replaceItems); bool changed = !string.Equals(path, newPath, StringComparison.Ordinal); if (!Options.OmitPath && changed) { LogHelpers.WritePath( result, replaceItems, baseDirectoryPath, relativePath: Options.DisplayRelativePath, colors: Colors.Matched_Path, matchColors: (Options.HighlightMatch) ? Colors.Match : default,
public bool TryParse(RenameCommandOptions options) { var baseOptions = (DeleteOrRenameCommandOptions)options; if (!TryParse(baseOptions)) { return(false); } options = (RenameCommandOptions)baseOptions; if (!TryParseHighlightOptions( Highlight, out HighlightOptions highlightOptions, defaultValue: HighlightOptions.Replacement, provider: OptionValueProviders.RenameHighlightOptionsProvider)) { return(false); } if (!FilterParser.TryParse( Name, OptionNames.Name, OptionValueProviders.PatternOptionsWithoutGroupAndNegativeProvider, out Filter? nameFilter, out FileNamePart namePart, namePartProvider: OptionValueProviders.NamePartKindProvider_WithoutFullName)) { return(false); } if (!FilterParser.TryParse( Content, OptionNames.Content, OptionValueProviders.PatternOptionsWithoutPartProvider, out Filter? contentFilter, allowNull: true)) { return(false); } if (!TryParseReplacement(Replacement, out string?replacement, out MatchEvaluator? matchEvaluator)) { return(false); } if (matchEvaluator == null && Evaluator != null) { LogHelpers.WriteObsoleteWarning( $"Option '{OptionNames.GetHelpText(OptionNames.Evaluator)}' is obsolete. " + $"Use option '{OptionNames.GetHelpText(OptionNames.Replacement)}' instead."); if (!DelegateFactory.TryCreateFromAssembly(Evaluator, typeof(string), typeof(Match), out matchEvaluator)) { return(false); } } if (!TryParseReplaceOptions( Modify, OptionNames.Modify, replacement, matchEvaluator, out ReplaceOptions? replaceOptions)) { return(false); } if (!TryParseAsEnum( Conflict, OptionNames.Conflict, out ConflictResolution conflictResolution, defaultValue: ConflictResolution.Ask, provider: OptionValueProviders.ConflictResolutionProvider_WithoutSuffix)) { return(false); } if (!TryParseDisplay( values: Display, optionName: OptionNames.Display, contentDisplayStyle: out ContentDisplayStyle? contentDisplayStyle, pathDisplayStyle: out PathDisplayStyle? pathDisplayStyle, lineDisplayOptions: out LineDisplayOptions lineDisplayOptions, lineContext: out LineContext lineContext, displayParts: out DisplayParts displayParts, fileProperties: out ImmutableArray <FileProperty> fileProperties, indent: out string?indent, separator: out string?separator, noAlign: out bool noAlign, contentDisplayStyleProvider: OptionValueProviders.ContentDisplayStyleProvider, pathDisplayStyleProvider: OptionValueProviders.PathDisplayStyleProvider_Rename)) { return(false); } if (pathDisplayStyle == PathDisplayStyle.Relative && options.Paths.Length > 1 && options.SortOptions != null) { pathDisplayStyle = PathDisplayStyle.Full; } options.Format = new OutputDisplayFormat( contentDisplayStyle: contentDisplayStyle ?? ContentDisplayStyle.Omit, pathDisplayStyle: pathDisplayStyle ?? PathDisplayStyle.Full, lineOptions: lineDisplayOptions, lineContext: lineContext, displayParts: displayParts, fileProperties: fileProperties, indent: indent, separator: separator, alignColumns: !noAlign); options.HighlightOptions = highlightOptions; options.SearchTarget = GetSearchTarget(); options.ReplaceOptions = replaceOptions; options.AskMode = (Ask) ? AskMode.File : AskMode.None; options.DryRun = DryRun; options.NameFilter = nameFilter; options.NamePart = namePart; options.ContentFilter = contentFilter; options.MaxMatchingFiles = MaxCount; options.ConflictResolution = conflictResolution; options.Interactive = Interactive; return(true); }
public static bool TryParseDisplay( IEnumerable <string> values, string optionName, out ContentDisplayStyle?contentDisplayStyle, out PathDisplayStyle?pathDisplayStyle, out LineDisplayOptions lineDisplayOptions, out LineContext lineContext, out DisplayParts displayParts, out ImmutableArray <FileProperty> fileProperties, out string?indent, out string?separator, out bool noAlign, OptionValueProvider?contentDisplayStyleProvider = null, OptionValueProvider?pathDisplayStyleProvider = null) { contentDisplayStyle = null; pathDisplayStyle = null; lineDisplayOptions = LineDisplayOptions.None; lineContext = default; displayParts = DisplayParts.None; fileProperties = ImmutableArray <FileProperty> .Empty; indent = null; separator = null; noAlign = false; ImmutableArray <FileProperty> .Builder?builder = null; foreach (string value in values) { int index = value.IndexOf('='); if (index >= 0) { string key = value.Substring(0, index); string value2 = value.Substring(index + 1); if (key == "t") { LogHelpers.WriteObsoleteWarning($"Value '{key}' is obsolete. " + $"Use value '{OptionValues.Display_Context.HelpValue}' instead."); key = OptionValues.Display_Context.ShortKey; } else if (key == "ta") { LogHelpers.WriteObsoleteWarning($"Value '{key}' is obsolete. " + $"Use value '{OptionValues.Display_ContextAfter.HelpValue}' instead."); key = OptionValues.Display_ContextAfter.ShortKey; } else if (key == "tb") { LogHelpers.WriteObsoleteWarning($"Value '{key}' is obsolete. " + $"Use value '{OptionValues.Display_ContextBefore.HelpValue}' instead."); key = OptionValues.Display_ContextBefore.ShortKey; } if (OptionValues.Display_Content.IsKeyOrShortKey(key)) { if (!TryParseAsEnum( value2, optionName, out ContentDisplayStyle contentDisplayStyle2, provider: contentDisplayStyleProvider)) { return(false); } contentDisplayStyle = contentDisplayStyle2; } else if (OptionValues.Display_Path.IsKeyOrShortKey(key)) { if (!TryParseAsEnum( value2, optionName, out PathDisplayStyle pathDisplayStyle2, provider: pathDisplayStyleProvider)) { return(false); } pathDisplayStyle = pathDisplayStyle2; } else if (OptionValues.Display_Indent.IsKeyOrShortKey(key)) { indent = value2; } else if (OptionValues.Display_Separator.IsKeyOrShortKey(key)) { separator = RegexEscape.ConvertCharacterEscapes(value2); } else if (OptionValues.Display_Context.IsKeyOrShortKey(key)) { if (!TryParseCount(value2, OptionNames.Display, out int count, value)) { return(false); } lineContext = new LineContext(count); } else if (OptionValues.Display_ContextBefore.IsKeyOrShortKey(key)) { if (!TryParseCount(value2, OptionNames.Display, out int before, value)) { return(false); } lineContext = lineContext.WithBefore(before); } else if (OptionValues.Display_ContextAfter.IsKeyOrShortKey(key)) { if (!TryParseCount(value2, OptionNames.Display, out int after, value)) { return(false); } lineContext = lineContext.WithAfter(after); } else { WriteOptionError(value, optionName, OptionValueProviders.DisplayProvider); return(false); } } else if (OptionValues.Display_Summary.IsValueOrShortValue(value)) { displayParts |= DisplayParts.Summary; } else if (OptionValues.Display_Count.IsValueOrShortValue(value)) { displayParts |= DisplayParts.Count; } else if (OptionValues.Display_CreationTime.IsValueOrShortValue(value)) { (builder ??= ImmutableArray.CreateBuilder <FileProperty>()).Add(FileProperty.CreationTime); } else if (OptionValues.Display_ModifiedTime.IsValueOrShortValue(value)) { (builder ??= ImmutableArray.CreateBuilder <FileProperty>()).Add(FileProperty.ModifiedTime); } else if (OptionValues.Display_Size.IsValueOrShortValue(value)) { (builder ??= ImmutableArray.CreateBuilder <FileProperty>()).Add(FileProperty.Size); } else if (OptionValues.Display_LineNumber.IsValueOrShortValue(value)) { lineDisplayOptions |= LineDisplayOptions.IncludeLineNumber; } else if (OptionValues.Display_TrimLine.IsValueOrShortValue(value)) { lineDisplayOptions |= LineDisplayOptions.TrimLine; } else if (OptionValues.Display_TrimLine.IsValueOrShortValue(value)) { lineDisplayOptions |= LineDisplayOptions.TrimLine; } else if (OptionValues.Display_TrimLine.IsValueOrShortValue(value)) { lineDisplayOptions |= LineDisplayOptions.TrimLine; } else if (OptionValues.Display_NoAlign.IsValueOrShortValue(value)) { noAlign = true; } else { WriteOptionError(value, optionName, OptionValueProviders.DisplayProvider); return(false); } } if (builder != null) { fileProperties = builder.ToImmutableArray(); } return(true); }
public static bool TryParseModifyOptions( IEnumerable <string> values, string optionName, EnumerableModifier <string>?modifier, [NotNullWhen(true)] out ModifyOptions?modifyOptions, out bool aggregateOnly) { modifyOptions = null; aggregateOnly = false; var sortProperty = ValueSortProperty.None; List <string>?options = null; foreach (string value in values) { int index = value.IndexOf('='); if (index >= 0) { string key = value.Substring(0, index); string value2 = value.Substring(index + 1); if (OptionValues.SortBy.IsKeyOrShortKey(key)) { if (!TryParseAsEnum( value2, optionName, out sortProperty, provider: OptionValueProviders.ValueSortPropertyProvider)) { return(false); } } else { WriteOptionError(value, optionName, OptionValueProviders.ModifyFlagsProvider); return(false); } } else { string value2 = value; if (value2 == "ao") { LogHelpers.WriteObsoleteWarning( $"Value '{value2}' is obsolete. Use value '{OptionValues.ModifyFlags_AggregateOnly.HelpValue}' instead."); value2 = OptionValues.ModifyFlags_AggregateOnly.ShortValue; } (options ??= new List <string>()).Add(value2); } } var modifyFlags = ModifyFlags.None; if (options != null && !TryParseAsEnumFlags( options, optionName, out modifyFlags, provider: OptionValueProviders.ModifyFlagsProvider)) { return(false); } ModifyFlags except_Intersect_Group = modifyFlags & ModifyFlags.Except_Intersect_Group; if (except_Intersect_Group != ModifyFlags.None && except_Intersect_Group != ModifyFlags.Except && except_Intersect_Group != ModifyFlags.Intersect && except_Intersect_Group != ModifyFlags.Group) { WriteError($"Values '{OptionValues.ModifyFlags_Except.HelpValue}', " + $"'{OptionValues.ModifyFlags_Intersect.HelpValue}' and " + $"'{OptionValues.ModifyFlags_Group.HelpValue}' cannot be used at the same time."); return(false); } var functions = ModifyFunctions.None; if ((modifyFlags & ModifyFlags.Distinct) != 0) { functions |= ModifyFunctions.Distinct; } if ((modifyFlags & ModifyFlags.Ascending) != 0) { functions |= ModifyFunctions.Sort; } if ((modifyFlags & ModifyFlags.Descending) != 0) { functions |= ModifyFunctions.SortDescending; } if ((modifyFlags & ModifyFlags.Except) != 0) { functions |= ModifyFunctions.Except; } if ((modifyFlags & ModifyFlags.Intersect) != 0) { functions |= ModifyFunctions.Intersect; } if ((modifyFlags & ModifyFlags.Group) != 0) { functions |= ModifyFunctions.Group; } if ((modifyFlags & ModifyFlags.RemoveEmpty) != 0) { functions |= ModifyFunctions.RemoveEmpty; } if ((modifyFlags & ModifyFlags.RemoveWhiteSpace) != 0) { functions |= ModifyFunctions.RemoveWhiteSpace; } if ((modifyFlags & ModifyFlags.TrimStart) != 0) { functions |= ModifyFunctions.TrimStart; } if ((modifyFlags & ModifyFlags.TrimEnd) != 0) { functions |= ModifyFunctions.TrimEnd; } if ((modifyFlags & ModifyFlags.ToLower) != 0) { functions |= ModifyFunctions.ToLower; } if ((modifyFlags & ModifyFlags.ToUpper) != 0) { functions |= ModifyFunctions.ToUpper; } if (sortProperty != ValueSortProperty.None && (functions & ModifyFunctions.Sort) == 0 && (functions & ModifyFunctions.SortDescending) == 0) { functions |= ModifyFunctions.Sort; } aggregateOnly = (modifyFlags & ModifyFlags.AggregateOnly) != 0; if (modifyFlags != ModifyFlags.None || functions != ModifyFunctions.None || modifier != null) { modifyOptions = new ModifyOptions( functions: functions, aggregate: (modifyFlags & ModifyFlags.Aggregate) != 0 || aggregateOnly, ignoreCase: (modifyFlags & ModifyFlags.IgnoreCase) != 0, cultureInvariant: (modifyFlags & ModifyFlags.CultureInvariant) != 0, sortProperty: sortProperty, modifier: modifier); } else { modifyOptions = ModifyOptions.Default; } return(true); }
public bool TryParse(ReplaceCommandOptions options) { if (!TryParseAsEnum( Pipe, OptionNames.Pipe, out PipeMode pipeMode, PipeMode.None, OptionValueProviders.PipeMode)) { return(false); } if (pipeMode == PipeMode.None) { if (Console.IsInputRedirected) { PipeMode = PipeMode.Text; } } else { if (!Console.IsInputRedirected) { WriteError("Redirected/piped input is required " + $"when option '{OptionNames.GetHelpText(OptionNames.Pipe)}' is specified."); return(false); } PipeMode = pipeMode; } if (!TryParseProperties(Ask, Name, options)) { return(false); } var baseOptions = (FileSystemCommandOptions)options; if (!TryParse(baseOptions)) { return(false); } options = (ReplaceCommandOptions)baseOptions; if (!FilterParser.TryParse( Content, OptionNames.Content, OptionValueProviders.PatternOptionsWithoutGroupAndPartAndNegativeProvider, out Filter? contentFilter)) { return(false); } if (!TryParseReplacement(Replacement, out string?replacement, out MatchEvaluator? matchEvaluator)) { return(false); } if (matchEvaluator == null && Evaluator != null) { LogHelpers.WriteObsoleteWarning( $"Option '{OptionNames.GetHelpText(OptionNames.Evaluator)}' is obsolete. " + $"Use option '{OptionNames.GetHelpText(OptionNames.Replacement)}' instead."); if (!DelegateFactory.TryCreateFromAssembly(Evaluator, typeof(string), typeof(Match), out matchEvaluator)) { return(false); } } if (!TryParseReplaceOptions( Modify, OptionNames.Modify, replacement, matchEvaluator, out ReplaceOptions? replaceOptions)) { return(false); } if (!TryParseMaxCount(MaxCount, out int maxMatchingFiles, out int maxMatchesInFile)) { return(false); } string?input = null; if (Input.Any() && !TryParseInput(Input, out input)) { return(false); } if (pipeMode != PipeMode.Paths && Console.IsInputRedirected) { if (input != null) { WriteError("Cannot use both redirected/piped input and " + $"option '{OptionNames.GetHelpText(OptionNames.Input)}'."); return(false); } if (contentFilter == null) { WriteError($"Option '{OptionNames.GetHelpText(OptionNames.Content)}' is required " + "when redirected/piped input is used as a text to be searched."); return(false); } input = ConsoleHelpers.ReadRedirectedInput(); } ContentDisplayStyle contentDisplayStyle; PathDisplayStyle pathDisplayStyle; if (!TryParseDisplay( values: Display, optionName: OptionNames.Display, contentDisplayStyle: out ContentDisplayStyle? contentDisplayStyle2, pathDisplayStyle: out PathDisplayStyle? pathDisplayStyle2, lineDisplayOptions: out LineDisplayOptions lineDisplayOptions, lineContext: out LineContext lineContext, displayParts: out DisplayParts displayParts, fileProperties: out ImmutableArray <FileProperty> fileProperties, indent: out string?indent, separator: out string?separator, noAlign: out bool noAlign, contentDisplayStyleProvider: OptionValueProviders.ContentDisplayStyleProvider_WithoutUnmatchedLines, pathDisplayStyleProvider: OptionValueProviders.PathDisplayStyleProvider)) { return(false); } if (contentDisplayStyle2 != null) { if (options.AskMode == AskMode.Value && contentDisplayStyle2 == ContentDisplayStyle.AllLines) { string helpValue = OptionValueProviders.ContentDisplayStyleProvider .GetValue(nameof(ContentDisplayStyle.AllLines)) .HelpValue; string helpValue2 = OptionValueProviders.AskModeProvider.GetValue(nameof(AskMode.Value)).HelpValue; WriteError($"Option '{OptionNames.GetHelpText(OptionNames.Display)}' cannot have value " + $"'{helpValue}' when option '{OptionNames.GetHelpText(OptionNames.Ask)}' has value '{helpValue2}'."); return(false); } contentDisplayStyle = contentDisplayStyle2.Value; } else if (Input.Any()) { contentDisplayStyle = ContentDisplayStyle.AllLines; } else { contentDisplayStyle = ContentDisplayStyle.Line; } pathDisplayStyle = pathDisplayStyle2 ?? PathDisplayStyle.Full; if (pathDisplayStyle == PathDisplayStyle.Relative && options.Paths.Length > 1 && options.SortOptions != null) { pathDisplayStyle = PathDisplayStyle.Full; } if (!TryParseHighlightOptions( Highlight, out HighlightOptions highlightOptions, defaultValue: HighlightOptions.Replacement, contentDisplayStyle: contentDisplayStyle, provider: OptionValueProviders.ReplaceHighlightOptionsProvider)) { return(false); } options.Format = new OutputDisplayFormat( contentDisplayStyle: contentDisplayStyle, pathDisplayStyle: pathDisplayStyle, lineOptions: lineDisplayOptions, lineContext: lineContext, displayParts: displayParts, fileProperties: fileProperties, indent: indent, separator: separator, alignColumns: !noAlign); options.HighlightOptions = highlightOptions; options.ContentFilter = contentFilter; options.ReplaceOptions = replaceOptions; options.Input = input; options.DryRun = DryRun; options.MaxMatchesInFile = maxMatchesInFile; options.MaxMatchingFiles = maxMatchingFiles; options.MaxTotalMatches = 0; options.Interactive = Interactive; #if DEBUG // --find if (Find) { options.ReplaceOptions = ReplaceOptions.Empty; options.HighlightOptions = HighlightOptions.Match; options.DryRun = true; } #endif return(true); }
protected virtual void ExecuteOperation(SearchContext context, string sourcePath, string destinationPath, bool isDirectory, string indent) { bool fileExists = File.Exists(destinationPath); bool directoryExists = !fileExists && Directory.Exists(destinationPath); bool ask = false; if (isDirectory) { if (fileExists) { ask = true; } else if (directoryExists) { if (File.GetAttributes(sourcePath) == File.GetAttributes(destinationPath)) { return; } ask = true; } } else if (fileExists) { if (Options.CompareOptions != FileCompareOptions.None && FileSystemHelpers.FileEquals(sourcePath, destinationPath, Options.CompareOptions)) { return; } ask = true; } else if (directoryExists) { ask = true; } if (ask && ConflictResolution == ConflictResolution.Skip) { return; } if (!isDirectory && fileExists && ConflictResolution == ConflictResolution.Suffix) { destinationPath = FileSystemHelpers.CreateNewFilePath(destinationPath); } if (!Options.OmitPath) { LogHelpers.WritePath(destinationPath, basePath: Target, relativePath: Options.DisplayRelativePath, colors: Colors.Matched_Path, indent: indent, verbosity: Verbosity.Minimal); WriteLine(Verbosity.Minimal); } if (ask && ConflictResolution == ConflictResolution.Ask) { string question; if (directoryExists) { question = (isDirectory) ? "Update directory attributes?" : "Overwrite directory?"; } else { question = "Overwrite file?"; } DialogResult dialogResult = ConsoleHelpers.Ask(question, indent); switch (dialogResult) { case DialogResult.Yes: { break; } case DialogResult.YesToAll: { ConflictResolution = ConflictResolution.Overwrite; break; } case DialogResult.No: case DialogResult.None: { return; } case DialogResult.NoToAll: { ConflictResolution = ConflictResolution.Skip; return; } case DialogResult.Cancel: { context.TerminationReason = TerminationReason.Canceled; return; } default: { throw new InvalidOperationException($"Unknown enum value '{dialogResult}'."); } } } if (isDirectory) { if (directoryExists) { if (!Options.DryRun) { FileSystemHelpers.UpdateAttributes(sourcePath, destinationPath); } } else { if (fileExists && !Options.DryRun) { File.Delete(destinationPath); } if (!Options.DryRun) { Directory.CreateDirectory(destinationPath); } } context.Telemetry.ProcessedDirectoryCount++; } else { if (fileExists) { if (!Options.DryRun) { File.Delete(destinationPath); } } else if (directoryExists) { if (!Options.DryRun) { Directory.Delete(destinationPath, recursive: true); } } else if (!Options.DryRun) { Directory.CreateDirectory(Path.GetDirectoryName(destinationPath)); } if (!Options.DryRun) { ExecuteOperation(sourcePath, destinationPath); } context.Telemetry.ProcessedFileCount++; } }
protected virtual DialogResult? ExecuteOperation( SearchContext context, string sourcePath, string destinationPath, bool isDirectory, string indent) { bool fileExists = File.Exists(destinationPath); bool directoryExists = !fileExists && Directory.Exists(destinationPath); var ask = false; if (isDirectory) { if (fileExists) { ask = true; } else if (directoryExists) { if (Options.StructureOnly && File.GetAttributes(sourcePath) == File.GetAttributes(destinationPath)) { return null; } ask = true; } } else if (fileExists) { if (Options.CompareOptions != FileCompareOptions.None && FileSystemHelpers.FileEquals(sourcePath, destinationPath, Options.CompareOptions)) { return null; } ask = true; } else if (directoryExists) { ask = true; } if (ask && ConflictResolution == ConflictResolution.Skip) { return null; } if (ConflictResolution == ConflictResolution.Suffix && ((isDirectory && directoryExists) || (!isDirectory && fileExists))) { destinationPath = FileSystemHelpers.CreateNewFilePath(destinationPath); } if (!Options.OmitPath) { LogHelpers.WritePath( destinationPath, basePath: Target, relativePath: Options.DisplayRelativePath, colors: default,