Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/actions/spell-check/expect.txt
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,7 @@
cursorpos
customaction
CUSTOMACTIONTEST
CUSTOMFORMATPLACEHOLDER
CVal
cvd
CVirtual
Expand Down Expand Up @@ -1501,7 +1502,7 @@
sigdn
SIGNINGSCENARIO
signtool
Signtool

Check warning on line 1505 in .github/actions/spell-check/expect.txt

View workflow job for this annotation

GitHub Actions / Check Spelling

`Signtool` is ignored by check spelling because another more general variant is also in expect. (ignored-expect-variant)
SINGLEKEY
sipolicy
SIZEBOX
Expand Down Expand Up @@ -1648,6 +1649,7 @@
templatenamespace
testprocess
TEXCOORD
TEXTBOXNEWLINE
TEXTEXTRACTOR
TEXTINCLUDE
tfopen
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,9 @@
using System.Runtime.CompilerServices;
using Microsoft.CommandPalette.Extensions.Toolkit;

[assembly: InternalsVisibleTo("Microsoft.PowerToys.Run.Plugin.TimeDate.UnitTests")]

namespace Microsoft.CmdPal.Ext.TimeDate.Helpers;

internal class AvailableResult
internal sealed class AvailableResult
{
/// <summary>
/// Gets or sets the time/date value
Expand All @@ -30,6 +28,11 @@ internal class AvailableResult
/// </summary>
internal ResultIconType IconType { get; set; }

/// <summary>
/// Gets or sets a value to show additional error details
/// </summary>
internal string ErrorDetails { get; set; } = string.Empty;

/// <summary>
/// Returns the path to the icon
/// </summary>
Expand All @@ -42,6 +45,7 @@ public IconInfo GetIconInfo()
ResultIconType.Time => ResultHelper.TimeIcon,
ResultIconType.Date => ResultHelper.CalendarIcon,
ResultIconType.DateTime => ResultHelper.TimeDateIcon,
ResultIconType.Error => ResultHelper.ErrorIcon,
_ => null,
};
}
Expand All @@ -53,6 +57,7 @@ public ListItem ToListItem()
Title = this.Value,
Subtitle = this.Label,
Icon = this.GetIconInfo(),
Details = string.IsNullOrEmpty(this.ErrorDetails) ? null : new Details() { Body = this.ErrorDetails },
};
}

Expand Down Expand Up @@ -81,4 +86,5 @@ public enum ResultIconType
Time,
Date,
DateTime,
Error,
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text.RegularExpressions;

namespace Microsoft.CmdPal.Ext.TimeDate.Helpers;

Expand Down Expand Up @@ -69,6 +70,86 @@ internal static List<AvailableResult> GetList(bool isKeywordSearch, SettingsMana
var era = DateTimeFormatInfo.CurrentInfo.GetEraName(calendar.GetEra(dateTimeNow));
var eraShort = DateTimeFormatInfo.CurrentInfo.GetAbbreviatedEraName(calendar.GetEra(dateTimeNow));

// Custom formats
foreach (var f in settings.CustomFormats)
{
var formatParts = f.Split("=", 2, StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
var formatSyntax = formatParts.Length == 2 ? formatParts[1] : string.Empty;
var searchTags = ResultHelper.SelectStringFromResources(isSystemDateTime, "Microsoft_plugin_timedate_SearchTagCustom");
var dtObject = dateTimeNow;

// If Length = 0 then empty string.
if (formatParts.Length >= 1)
{
try
{
// Verify and check input and update search tags
if (formatParts.Length == 1)
{
throw new FormatException("Format syntax part after equal sign is missing.");
}

var containsCustomSyntax = TimeAndDateHelper.StringContainsCustomFormatSyntax(formatSyntax);
if (formatSyntax.StartsWith("UTC:", StringComparison.InvariantCulture))
{
searchTags = ResultHelper.SelectStringFromResources(isSystemDateTime, "Microsoft_plugin_timedate_SearchTagCustomUtc");
dtObject = dateTimeNowUtc;
}

// Get formated date
var value = TimeAndDateHelper.ConvertToCustomFormat(dtObject, unixTimestamp, unixTimestampMilliseconds, weekOfYear, eraShort, Regex.Replace(formatSyntax, "^UTC:", string.Empty), firstWeekRule, firstDayOfTheWeek);
try
{
value = dtObject.ToString(value, CultureInfo.CurrentCulture);
}
catch
{
if (!containsCustomSyntax)
{
throw;
}
else
{
// Do not fail as we have custom format syntax. Instead fix backslashes.
value = Regex.Replace(value, @"(?<!\\)\\", string.Empty).Replace("\\\\", "\\");
}
}

// Add result
results.Add(new AvailableResult()
{
Value = value,
Label = formatParts[0],
AlternativeSearchTag = searchTags,
IconType = ResultIconType.DateTime,
});
}
catch (ArgumentOutOfRangeException e)
{
results.Add(new AvailableResult()
{
Value = Resources.Microsoft_plugin_timedate_ErrorConvertCustomFormat,
Label = formatParts[0] + " - " + Resources.Microsoft_plugin_timedate_show_details,
AlternativeSearchTag = searchTags,
IconType = ResultIconType.Error,
ErrorDetails = e.Message,
});
}
catch (Exception e)
{
results.Add(new AvailableResult()
{
Value = Resources.Microsoft_plugin_timedate_InvalidCustomFormat + " " + formatSyntax,
Label = formatParts[0] + " - " + Resources.Microsoft_plugin_timedate_show_details,
AlternativeSearchTag = searchTags,
IconType = ResultIconType.Error,
ErrorDetails = e.Message,
});
}
}
}

// Predefined formats
results.AddRange(new[]
{
new AvailableResult()
Expand Down Expand Up @@ -149,6 +230,13 @@ internal static List<AvailableResult> GetList(bool isKeywordSearch, SettingsMana
IconType = ResultIconType.Date,
},
new AvailableResult()
{
Value = DateTime.DaysInMonth(dateTimeNow.Year, dateTimeNow.Month).ToString(CultureInfo.CurrentCulture),
Label = Resources.Microsoft_plugin_timedate_DaysInMonth,
AlternativeSearchTag = ResultHelper.SelectStringFromResources(isSystemDateTime, "Microsoft_plugin_timedate_SearchTagDate"),
IconType = ResultIconType.Date,
},
new AvailableResult()
{
Value = dateTimeNow.DayOfYear.ToString(CultureInfo.CurrentCulture),
Label = Resources.Microsoft_plugin_timedate_DayOfYear,
Expand Down Expand Up @@ -198,6 +286,13 @@ internal static List<AvailableResult> GetList(bool isKeywordSearch, SettingsMana
IconType = ResultIconType.Date,
},
new AvailableResult()
{
Value = DateTime.IsLeapYear(dateTimeNow.Year) ? Resources.Microsoft_plugin_timedate_LeapYear : Resources.Microsoft_plugin_timedate_NoLeapYear,
Label = Resources.Microsoft_plugin_timedate_LeapYear,
AlternativeSearchTag = ResultHelper.SelectStringFromResources(isSystemDateTime, "Microsoft_plugin_timedate_SearchTagDate"),
IconType = ResultIconType.Date,
},
new AvailableResult()
{
Value = era,
Label = Resources.Microsoft_plugin_timedate_Era,
Expand All @@ -218,13 +313,31 @@ internal static List<AvailableResult> GetList(bool isKeywordSearch, SettingsMana
AlternativeSearchTag = ResultHelper.SelectStringFromResources(isSystemDateTime, "Microsoft_plugin_timedate_SearchTagDate"),
IconType = ResultIconType.Date,
},
new AvailableResult()
});

try
{
results.Add(new AvailableResult()
{
Value = dateTimeNow.ToFileTime().ToString(CultureInfo.CurrentCulture),
Label = Resources.Microsoft_plugin_timedate_WindowsFileTime,
AlternativeSearchTag = ResultHelper.SelectStringFromResources(isSystemDateTime, "Microsoft_plugin_timedate_SearchTagFormat"),
IconType = ResultIconType.DateTime,
},
});
}
catch
{
results.Add(new AvailableResult()
{
Value = Resources.Microsoft_plugin_timedate_ErrorConvertWft,
Label = Resources.Microsoft_plugin_timedate_WindowsFileTime,
AlternativeSearchTag = ResultHelper.SelectStringFromResources(isSystemDateTime, "Microsoft_plugin_timedate_SearchTagFormat"),
IconType = ResultIconType.Error,
});
}

results.AddRange(new[]
{
new AvailableResult()
{
Value = dateTimeNowUtc.ToString("u"),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,8 @@
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using System;
using System.Globalization;
using System.IO;
using Microsoft.CommandPalette.Extensions;
using Microsoft.CommandPalette.Extensions.Toolkit;

namespace Microsoft.CmdPal.Ext.TimeDate.Helpers;
Expand Down Expand Up @@ -33,21 +32,24 @@ internal static string SelectStringFromResources(bool isSystemTimeDate, string s

public static IconInfo TimeDateIcon { get; } = new IconInfo("\uEC92");

public static IconInfo ErrorIcon { get; } = IconHelpers.FromRelativePaths("Microsoft.CmdPal.Ext.TimeDate\\Assets\\Warning.light.png", "Microsoft.CmdPal.Ext.TimeDate\\Assets\\Warning.dark.png");

/// <summary>
/// Gets a result with an error message that only numbers can't be parsed
/// Gets a result with an error message that input can't be parsed
/// </summary>
/// <returns>Element of type <see cref="Result"/>.</returns>
internal static ListItem CreateNumberErrorResult() => new ListItem(new NoOpCommand())
{
Title = Resources.Microsoft_plugin_timedate_ErrorResultTitle,
Subtitle = Resources.Microsoft_plugin_timedate_ErrorResultSubTitle,
Icon = IconHelpers.FromRelativePaths("Microsoft.CmdPal.Ext.TimeDate\\Assets\\Warning.light.png", "Microsoft.CmdPal.Ext.TimeDate\\Assets\\Warning.dark.png"),
};

#pragma warning disable CA1863 // Use 'CompositeFormat'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you please use compositeFormat to remove this disable flag?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

but why. we have to read it every time because of translation. Or am I wrong?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No.. you are right.

just because I don't like to add suppress config in source code. haha.

leaving it here is also acceptable for me.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Then let's merge. Or should I move/duplicate the existing comment?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Merged

internal static ListItem CreateInvalidInputErrorResult() => new ListItem(new NoOpCommand())
{
Title = Resources.Microsoft_plugin_timedate_InvalidInput_ErrorMessageTitle,
Subtitle = Resources.Microsoft_plugin_timedate_InvalidInput_ErrorMessageSubTitle,
Icon = IconHelpers.FromRelativePaths("Microsoft.CmdPal.Ext.TimeDate\\Assets\\Warning.light.png", "Microsoft.CmdPal.Ext.TimeDate\\Assets\\Warning.dark.png"),
Icon = ErrorIcon,
Details = new Details()
{
Title = Resources.Microsoft_plugin_timedate_InvalidInput_DetailsHeader,

// Because of translation we can't use 'CompositeFormat'.
Body = string.Format(CultureInfo.CurrentCulture, Resources.Microsoft_plugin_timedate_InvalidInput_SupportedInput, "**", "\n\n", "\n\n* "),
},
};
#pragma warning restore CA1863 // Use 'CompositeFormat'
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,11 @@ namespace Microsoft.CmdPal.Ext.TimeDate.Helpers;

public class SettingsManager : JsonSettingsManager
{
// Line break character used in WinUI3 TextBox and TextBlock.
private const char TEXTBOXNEWLINE = '\r';

private const string CUSTOMFORMATPLACEHOLDER = "MyFormat=dd-MMM-yyyy\rMySecondFormat=dddd (Da\\y nu\\mber: DOW)\rMyUtcFormat=UTC:hh:mm:ss";

private static readonly string _namespace = "timeDate";

private static string Namespaced(string propertyName) => $"{_namespace}.{propertyName}";
Expand Down Expand Up @@ -94,6 +99,12 @@ public class SettingsManager : JsonSettingsManager
Resources.Microsoft_plugin_timedate_SettingHideNumberMessageOnGlobalQuery,
true); // TODO -- double check default value

private readonly TextSetting _customFormats = new(
Namespaced(nameof(CustomFormats)),
Resources.Microsoft_plugin_timedate_Setting_CustomFormats,
Resources.Microsoft_plugin_timedate_Setting_CustomFormats + TEXTBOXNEWLINE + string.Format(CultureInfo.CurrentCulture, Resources.Microsoft_plugin_timedate_Setting_CustomFormatsDescription.ToString(), "DOW", "DIM", "WOM", "WOY", "EAB", "WFT", "UXT", "UMS", "OAD", "EXC", "EXF", "UTC:"),
string.Empty);

public int FirstWeekOfYear
{
get
Expand Down Expand Up @@ -142,6 +153,8 @@ public int FirstDayOfWeek

public bool HideNumberMessageOnGlobalQuery => _hideNumberMessageOnGlobalQuery.Value;

public List<string> CustomFormats => _customFormats.Value.Split(TEXTBOXNEWLINE).ToList();

internal static string SettingsJsonPath()
{
var directory = Utilities.BaseSettingsPath("Microsoft.CmdPal");
Expand All @@ -155,12 +168,18 @@ public SettingsManager()
{
FilePath = SettingsJsonPath();

Settings.Add(_firstWeekOfYear);
Settings.Add(_firstDayOfWeek);
/* The following two settings make no sense with current CmdPal behavior.
Settings.Add(_onlyDateTimeNowGlobal);
Settings.Add(_hideNumberMessageOnGlobalQuery); */

Settings.Add(_timeWithSeconds);
Settings.Add(_dateWithWeekday);
Settings.Add(_hideNumberMessageOnGlobalQuery);
Settings.Add(_firstWeekOfYear);
Settings.Add(_firstDayOfWeek);

_customFormats.Multiline = true;
_customFormats.Placeholder = CUSTOMFORMATPLACEHOLDER;
Settings.Add(_customFormats);

// Load settings from file upon initialization
LoadSettings();
Expand Down
Loading
Loading