-
Notifications
You must be signed in to change notification settings - Fork 1.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add experimental feature for font list command #4886
base: master
Are you sure you want to change the base?
Conversation
This comment has been minimized.
This comment has been minimized.
{ | ||
namespace | ||
{ | ||
std::vector<std::filesystem::path> GetFontFilePaths(const wil::com_ptr<IDWriteFontFace>& fontFace) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seeing all upper case for returned file paths, can we update the casing for readability?
~ wingetdev font list --family-name "CaskaydiaCove Nerd Font Mono"
Face Family Paths
-----------------------------------------------------------------------------------------------------------------------------------------------------------
book CaskaydiaCove Nerd Font Mono C:\USERS\<USER>\APPDATA\LOCAL\MICROSOFT\WINDOWS\FONTS\CASKAYDIA COVE NERD FONT COMPLETE MONO.TTF
regular CaskaydiaCove Nerd Font Mono C:\USERS\<USER>\APPDATA\LOCAL\MICROSOFT\WINDOWS\FONTS\CASKAYDIA COVE NERD FONT COMPLETE MONO REGULAR.OTF
italic CaskaydiaCove Nerd Font Mono C:\USERS\<USER>\APPDATA\LOCAL\MICROSOFT\WINDOWS\FONTS\CASKAYDIA COVE NERD FONT COMPLETE MONO ITALIC.OTF
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
May also need to consider anonymizing path...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we are given upper case from the API, I'm not sure it is worth the effort to use the filesystem to correct it back to the original casing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
May also need to consider anonymizing path...
And respecting the AnonymizeDisplayPaths setting
Found myself juggling more than once between |
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would be helpful as a reviewer if the PR description contained some examples of usage so that I could give feedback on the visual representation.
I also want to ensure that the ISource implementation containing installed items is well thought through to avoid the need to have specialized COM interfaces. It doesn't even have to be a SQLite index, but if we can align the font data to the existing model we can save a lot of work exposing it.
The fun thing we could do with a custom ISource is to have the search results QI into these DWrite interfaces.
src/AppInstallerCLICore/Argument.cpp
Outdated
@@ -198,6 +198,10 @@ namespace AppInstaller::CLI | |||
case Execution::Args::Type::IgnoreResumeLimit: | |||
return { type, "ignore-resume-limit"_liv, ArgTypeCategory::None }; | |||
|
|||
// Font command | |||
case Execution::Args::Type::FamilyName: | |||
return { type, "family-name"_liv, ArgTypeCategory::None }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is "family" enough? Or maybe have "family" as an alias unless you think there is going to be confusion with some future "family-X" argument.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@@ -121,4 +121,10 @@ | |||
<value>Not Localized</value> | |||
<comment>{Locked} This file is required to establish the basic expected subresource in the resource map. It is not used to facilitate localization with other projects.</comment> | |||
</data> | |||
<data name="FontListCommandShortDescription" xml:space="preserve"> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wrong file.
src/AppInstallerCommonCore/Fonts.cpp
Outdated
UINT32 fileCount = 0; | ||
THROW_IF_FAILED(fontFace->GetFiles(&fileCount, nullptr)); | ||
|
||
wil::com_ptr<IDWriteFontFile> fontFiles[8]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- static_assert that
sizeof(wil::com_ptr<IDWriteFontFile>) == sizeof(IDWriteFontFile*)
; means that it is a no-overhead smart pointer type and that you can use an array-like of them this way (regardless of the actual array-like type) - vector of
wil::com_ptr<IDWriteFontFile>
- resize to
fileCount
src/AppInstallerCommonCore/Fonts.cpp
Outdated
THROW_IF_FAILED(localLoader->GetFilePathLengthFromKey(fontFileReferenceKey, fontFileReferenceKeySize, &pathLength)); | ||
pathLength += 1; // Account for the trailing null terminator during allocation. | ||
|
||
wchar_t path[MAX_PATH]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You have a size already, allocate some memory (preferably directly in a string so that you don't have to copy it).
src/AppInstallerCommonCore/Fonts.cpp
Outdated
THROW_IF_FAILED(font->GetFaceNames(faceNames.addressof())); | ||
|
||
wchar_t localeNameBuffer[LOCALE_NAME_MAX_LENGTH]; | ||
const auto localeName = GetUserDefaultLocaleName(localeNameBuffer, LOCALE_NAME_MAX_LENGTH) ? localeNameBuffer : L"en-US"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We already have some locale functionality for choosing installers and settings around this. Prefer those methods over calling this function.
src/AppInstallerCommonCore/Fonts.cpp
Outdated
|
||
UINT32 faceNameIndex; | ||
BOOL faceNameExists; | ||
if (FAILED(faceNames->FindLocaleName(localeName, &faceNameIndex, &faceNameExists)) || !faceNameExists) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It doesn't seem like this chooses a "best" locale to use. We have the option of extracting all of the locale names and sorting them for best fit, much like installer selection. Not saying that we should, but a comment may be warranted.
return std::wstring(faceName); | ||
} | ||
|
||
std::wstring GetFontFamilyName(const wil::com_ptr<IDWriteFontFamily>& fontFamily) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is exactly the same function as GetFontFaceName
save for the input type and function that is called to get the IDWriteLocalizedStrings
. Move all of the "get the correct localized string from an IDWriteLocalizedStrings
" to a shared function.
src/AppInstallerCommonCore/Fonts.cpp
Outdated
|
||
FontFace fontFaceEntry; | ||
fontFaceEntry.Name = std::wstring(faceName); | ||
fontFaceEntry.FilePaths = filePaths; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Apply std::move
liberally through this type of function so that you aren't making a copy of something you are about to destroy anyway.
src/AppInstallerCommonCore/Fonts.cpp
Outdated
|
||
wil::com_ptr<IDWriteFontFamily> family; | ||
THROW_IF_FAILED(collection->GetFontFamily(familyIndex, family.addressof())); | ||
const auto fontCount = family->GetFontCount(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Factor the "create a FontFamily
from a IDWriteFontFamily
" into a shared function.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure the way you've implemented the font families allows for Substring matching. It seems that if --family-name
is present, you're expecting an exact match, which conflicts with the --exact
argument. I presume the behavior should be the same as winget list
where it defaults to a Substring match unless the --exact
argument is specified.
src/AppInstallerCLICore/Argument.cpp
Outdated
@@ -198,6 +198,10 @@ namespace AppInstaller::CLI | |||
case Execution::Args::Type::IgnoreResumeLimit: | |||
return { type, "ignore-resume-limit"_liv, ArgTypeCategory::None }; | |||
|
|||
// Font command | |||
case Execution::Args::Type::FamilyName: | |||
return { type, "family-name"_liv, ArgTypeCategory::None }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Argument::ForType(Args::Type::Exact), | ||
Argument::ForType(Args::Type::AuthenticationMode), | ||
Argument::ForType(Args::Type::AuthenticationAccount), | ||
Argument::ForType(Args::Type::AcceptSourceAgreements), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
-n / --count
?--scope
?-q / --query
?
Will FamilyName
be the default positional, so if a user typed winget font list Arial
it would be the same as winget font list --family-name Arial
?
{ | ||
struct InstalledFontFamiliesTableLine | ||
{ | ||
InstalledFontFamiliesTableLine(Utility::LocIndString familyName, int faceCount) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is LocIndString
sufficient for the family name and face name? If I recall correctly, it is just a wrapper around std::string
, will this appropriately handle family names that contain Unicode characters? Is it even possible for the names to contain Unicode characters?
bool isFirstLine = true; | ||
for (const auto& filePath : fontFace.FilePaths) | ||
{ | ||
if (isFirstLine) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure that I like the idea of having table lines that have some fields being empty. While it can be appealing visually, I know that someone out there will want to script against it (even when it makes its way into the PowerShell module).
You never know what someone will do with the output either - they could pipe it to Sort-Object
and then it would be really confusing since all the lines would be out of order and they wouldn't contain all the information necessary to stand independently
|
||
void ReportInstalledFontsResult(Execution::Context& context) | ||
{ | ||
if (context.Args.Contains(Args::Type::FamilyName)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will there be any provision for searching by Face Name? Not sure if it provides value or not
REQUIRE(installedFontFamilies.size() > 0); | ||
} | ||
|
||
TEST_CASE("GetSingleFontFamily", "[fonts]") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There should also be a test for getting multiple font families by substring, if that's planned for support?
PS C:\Users\jluedtk> [Windows.Media.Fonts]::SystemFontFamilies | Select-Object -Property Source | ? { $_ -match 'Book' }
Source
------
Book Antiqua
Bookman Old Style
Bookshelf Symbol 7
Century Schoolbook
Franklin Gothic Book
/// </summary> | ||
/// <param name="familyName">The font family name.</param> | ||
/// <returns>The specified font family if found.</returns> | ||
std::optional<FontFamily> GetInstalledFontFamily(const std::wstring& familyName); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems a bit odd to me to have both a singular and a pluralized version of effectively the same function, with the only difference being that one takes a parameter to search for. Wouldn't it be possible to simply have GetInstalledFontFamilies
with an optional parameter for the search string? Then if no families are found, you have an empty vector, if an exact match is found you'd have a vector with a single FontFamily
in it, and if no familyName
was specified, you'd have a vector of all the families.
@check-spelling-bot Report🔴 Please reviewSee the 📂 files view, the 📜action log, or 📝 job summary for details. Unrecognized words (1)Aggregrate Previously acknowledged words that are now absentAKV Asn azcopy clsid cobertura notmatch Peet REINSTALLMODE sas SASURL similarissues similaritytolerance templating typeparam 🫥Some files were automatically ignored 🙈These sample patterns would exclude them:
You should consider adding them to:
File matching is via Perl regular expressions. To check these files, more of their words need to be in the dictionary than not. You can use To accept these unrecognized words as correct and remove the previously acknowledged and now absent words and update file exclusions, you could run the following commands... in a clone of the [email protected]:ryfu-msft/winget-cli.git repository curl -s -S -L 'https://raw.githubusercontent.com/check-spelling/check-spelling/v0.0.22/apply.pl' |
perl - 'https://github.com/microsoft/winget-cli/actions/runs/11411808496/attempts/1' Warnings (1)See the 📂 files view, the 📜action log, or 📝 job summary for details.
See ℹ️ Event descriptions for more information. If the flagged items are 🤯 false positivesIf items relate to a ...
|
Related to:
Changes:
font
winget font
command withlist
subcommand.winget font list --family-name "Vivaldi"
will display all of the face names for the font familyVivalidi
. At this point, this must be an exact match, but eventually this will allow partial search queries once the font index is created (separate PR).