diff --git a/.config/configuration.vsEnterprise.winget b/.config/configuration.vsEnterprise.winget new file mode 100644 index 0000000000..589244063d --- /dev/null +++ b/.config/configuration.vsEnterprise.winget @@ -0,0 +1,43 @@ +# yaml-language-server: $schema=https://aka.ms/configuration-dsc-schema/0.2 +# Reference: https://github.com/microsoft/terminal/blob/main/README.md#developer-guidance +properties: + resources: + - resource: Microsoft.Windows.Settings/WindowsSettings + directives: + description: Enable Developer Mode + allowPrerelease: true + # Requires elevation for the set operation + securityContext: elevated + settings: + DeveloperMode: true + - resource: Microsoft.WinGet.DSC/WinGetPackage + id: powershell + directives: + description: Install PowerShell 7 + # Requires elevation for the set operation (i.e., installation) + securityContext: elevated + settings: + id: Microsoft.PowerShell + source: winget + - resource: Microsoft.WinGet.DSC/WinGetPackage + id: vsPackage + directives: + description: Install Visual Studio 2022 Enterprise (any edition is OK) + # Requires elevation for the set operation (i.e., installation) + securityContext: elevated + settings: + id: Microsoft.VisualStudio.2022.Enterprise + source: winget + - resource: Microsoft.VisualStudio.DSC/VSComponents + dependsOn: + - vsPackage + directives: + description: Install required VS workloads from project .vsconfig file + allowPrerelease: true + # Requires elevation for the get and set operations + securityContext: elevated + settings: + productId: Microsoft.VisualStudio.Product.Enterprise + channelId: VisualStudio.17.Release + vsConfigFile: '${WinGetConfigRoot}\..\.vsconfig' + configurationVersion: 0.2.0 diff --git a/.config/configuration.vsProfessional.winget b/.config/configuration.vsProfessional.winget new file mode 100644 index 0000000000..549b6227bb --- /dev/null +++ b/.config/configuration.vsProfessional.winget @@ -0,0 +1,43 @@ +# yaml-language-server: $schema=https://aka.ms/configuration-dsc-schema/0.2 +# Reference: https://github.com/microsoft/terminal/blob/main/README.md#developer-guidance +properties: + resources: + - resource: Microsoft.Windows.Settings/WindowsSettings + directives: + description: Enable Developer Mode + allowPrerelease: true + # Requires elevation for the set operation + securityContext: elevated + settings: + DeveloperMode: true + - resource: Microsoft.WinGet.DSC/WinGetPackage + id: powershell + directives: + description: Install PowerShell 7 + # Requires elevation for the set operation (i.e., installation) + securityContext: elevated + settings: + id: Microsoft.PowerShell + source: winget + - resource: Microsoft.WinGet.DSC/WinGetPackage + id: vsPackage + directives: + description: Install Visual Studio 2022 Professional (any edition is OK) + # Requires elevation for the set operation (i.e., installation) + securityContext: elevated + settings: + id: Microsoft.VisualStudio.2022.Professional + source: winget + - resource: Microsoft.VisualStudio.DSC/VSComponents + dependsOn: + - vsPackage + directives: + description: Install required VS workloads from project .vsconfig file + allowPrerelease: true + # Requires elevation for the get and set operations + securityContext: elevated + settings: + productId: Microsoft.VisualStudio.Product.Professional + channelId: VisualStudio.17.Release + vsConfigFile: '${WinGetConfigRoot}\..\.vsconfig' + configurationVersion: 0.2.0 diff --git a/.config/configuration.winget b/.config/configuration.winget new file mode 100644 index 0000000000..5d7823a002 --- /dev/null +++ b/.config/configuration.winget @@ -0,0 +1,43 @@ +# yaml-language-server: $schema=https://aka.ms/configuration-dsc-schema/0.2 +# Reference: https://github.com/microsoft/terminal/blob/main/README.md#developer-guidance +properties: + resources: + - resource: Microsoft.Windows.Settings/WindowsSettings + directives: + description: Enable Developer Mode + allowPrerelease: true + # Requires elevation for the set operation + securityContext: elevated + settings: + DeveloperMode: true + - resource: Microsoft.WinGet.DSC/WinGetPackage + id: powershell + directives: + description: Install PowerShell 7 + # Requires elevation for the set operation (i.e., installation) + securityContext: elevated + settings: + id: Microsoft.PowerShell + source: winget + - resource: Microsoft.WinGet.DSC/WinGetPackage + id: vsPackage + directives: + description: Install Visual Studio 2022 Community (any edition is OK) + # Requires elevation for the set operation (i.e., installation) + securityContext: elevated + settings: + id: Microsoft.VisualStudio.2022.Community + source: winget + - resource: Microsoft.VisualStudio.DSC/VSComponents + dependsOn: + - vsPackage + directives: + description: Install required VS workloads from project .vsconfig file + allowPrerelease: true + # Requires elevation for the get and set operations + securityContext: elevated + settings: + productId: Microsoft.VisualStudio.Product.Community + channelId: VisualStudio.17.Release + vsConfigFile: '${WinGetConfigRoot}\..\.vsconfig' + configurationVersion: 0.2.0 diff --git a/.github/ISSUE_TEMPLATE/Bug_Report.yml b/.github/ISSUE_TEMPLATE/Bug_Report.yml index 517f2bdc7e..2a647a35d5 100644 --- a/.github/ISSUE_TEMPLATE/Bug_Report.yml +++ b/.github/ISSUE_TEMPLATE/Bug_Report.yml @@ -1,6 +1,7 @@ name: "Bug report 🐛" description: Report errors or unexpected behavior labels: [Issue-Bug, Needs-Triage] +type: Bug body: - type: markdown attributes: @@ -12,7 +13,7 @@ body: - type: input attributes: label: Windows Terminal version - placeholder: "1.7.3651.0" + placeholder: "1.21.2701.0" description: | You can copy the version number from the About dialog. Open the About dialog by opening the menu with the "V" button (to the right of the "+" button that opens a new tab) and choosing About from the end of the list. validations: @@ -21,7 +22,7 @@ body: - type: input attributes: label: Windows build number - placeholder: "10.0.19042.0" + placeholder: "10.0.22621.0" description: | Please run `ver` or `[Environment]::OSVersion`. validations: @@ -32,9 +33,9 @@ body: label: Other Software description: If you're reporting a bug about our interaction with other software, what software? What versions? placeholder: | - vim 8.2 (inside WSL) - OpenSSH_for_Windows_8.1p1 - My Cool Application v0.3 (include a code snippet if it would help!) + vim 9.1 (inside WSL) + OpenSSH_for_Windows_9.5p1 + My Cool Application v0.4 (include a code snippet if it would help!) validations: required: false diff --git a/.github/ISSUE_TEMPLATE/Documentation_Issue.md b/.github/ISSUE_TEMPLATE/Documentation_Issue.md deleted file mode 100644 index 808bf81313..0000000000 --- a/.github/ISSUE_TEMPLATE/Documentation_Issue.md +++ /dev/null @@ -1,10 +0,0 @@ ---- -name: "Documentation Issue 📚" -about: Report issues in our documentation -title: '' -labels: Issue-Docs -assignees: '' - ---- - - diff --git a/.github/ISSUE_TEMPLATE/Feature_Request.md b/.github/ISSUE_TEMPLATE/Feature_Request.md deleted file mode 100644 index e7a9dca66a..0000000000 --- a/.github/ISSUE_TEMPLATE/Feature_Request.md +++ /dev/null @@ -1,35 +0,0 @@ ---- -name: "Feature Request/Idea 🚀" -about: Suggest a new feature or improvement (this does not mean you have to implement - it) -title: '' -labels: Issue-Feature -assignees: '' - ---- - - - -# Description of the new feature/enhancement - - - -# Proposed technical implementation details (optional) - - diff --git a/.github/ISSUE_TEMPLATE/Feature_Request.yml b/.github/ISSUE_TEMPLATE/Feature_Request.yml new file mode 100644 index 0000000000..1ec2fd32b8 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/Feature_Request.yml @@ -0,0 +1,20 @@ +name: "Feature Request/Idea 🚀" +description: Suggest a new feature or improvement (this does not mean you have to implement it) +labels: [Issue-Feature] +type: Feature +body: +- type: textarea + attributes: + label: Description of the new feature + description: A clear and concise description of what the problem is that the new feature would solve. + placeholder: | + ... and guess what? I have four Terminals. And I have a hover car, and a hover house. And my computer's a runner, and it shows. + validations: + required: true + +- type: textarea + attributes: + label: Proposed technical implementation details + description: This field is optional. If you have any ideas, let us know! + validations: + required: false diff --git a/.github/actions/spelling/allow/allow.txt b/.github/actions/spelling/allow/allow.txt index ef4f666f47..b347ec85b9 100644 --- a/.github/actions/spelling/allow/allow.txt +++ b/.github/actions/spelling/allow/allow.txt @@ -5,28 +5,36 @@ breadcrumbs ccmp ccon clickable +cmark CMMI colorbrewer +commandlines consvc copyable +CText dalet dcs deselection dialytika diffing +Dimidium dje downsides dze dzhe Emacspeak Fitt +flac FTCS gantt +gfm ghe gje godbolt +hstrings hyperlinking hyperlinks +Kbds kje libfuzzer liga @@ -44,6 +52,7 @@ mnt mru nje notwrapped +NTMTo ogonek overlined perlw @@ -53,6 +62,7 @@ ptys pwn pwshw qof +QOL qps quickfix rclt @@ -69,8 +79,10 @@ shcha similaritytolerance slnt stakeholders +subpage sustainability sxn +Tencent TLDR tonos toolset @@ -81,6 +93,7 @@ und vsdevcmd westus workarounds +WSLs wtconfig XBox YBox diff --git a/.github/actions/spelling/allow/apis.txt b/.github/actions/spelling/allow/apis.txt index 839fcbe76b..6670909587 100644 --- a/.github/actions/spelling/allow/apis.txt +++ b/.github/actions/spelling/allow/apis.txt @@ -43,6 +43,7 @@ DONTADDTORECENT DWMSBT DWMWA DWORDLONG +EMPH endfor ENDSESSION enumset @@ -62,11 +63,12 @@ GETDESKWALLPAPER GETHIGHCONTRAST GETMOUSEHOVERTIME GETTEXTLENGTH +HARDBREAKS Hashtable HIGHCONTRASTON HIGHCONTRASTW -hinternet HIGHQUALITYSCALE +hinternet HINTERNET hotkeys href @@ -96,11 +98,10 @@ IGraphics IImage IInheritable IMap -IMonarch +imm IObject iosfwd IPackage -IPeasant isa ISetup isspace @@ -114,6 +115,7 @@ IUri IVirtual KEYSELECT LCID +LINEBREAK llabs llu localtime @@ -142,11 +144,13 @@ NCHITTEST NCLBUTTONDBLCLK NCMOUSELEAVE NCMOUSEMOVE +NCPOINTERUPDATE NCRBUTTONDBLCLK NIF NIN NOAGGREGATION NOASYNC +NOBREAKS NOCHANGEDIR NOPROGRESS NOREDIRECTIONBITMAP @@ -155,6 +159,7 @@ NOTIFYBYPOS NOTIFYICON NOTIFYICONDATA ntprivapi +NTSYSCALLAPI numr oaidl ocidl @@ -173,6 +178,7 @@ PALLOC PATINVERT PEXPLICIT PICKFOLDERS +PINPUT pmr ptstr QUERYENDSESSION @@ -201,6 +207,7 @@ SINGLEUSE SIZENS smoothstep snprintf +SOFTBREAK spsc sregex SRWLOC @@ -216,6 +223,7 @@ Stubless Subheader Subpage syscall +syscolors SYSTEMBACKDROP TABROW TASKBARCREATED @@ -283,4 +291,5 @@ xtree xutility YIcon YMax +zstring zwstring diff --git a/.github/actions/spelling/candidate.patterns b/.github/actions/spelling/candidate.patterns index 80f31f92e4..5d93035f91 100644 --- a/.github/actions/spelling/candidate.patterns +++ b/.github/actions/spelling/candidate.patterns @@ -8,7 +8,7 @@ ^.*\b[Cc][Ss][Pp][Ee][Ll]{2}:\s*[Dd][Ii][Ss][Aa][Bb][Ll][Ee]-[Ll][Ii][Nn][Ee]\b # patch hunk comments -^\@\@ -\d+(?:,\d+|) \+\d+(?:,\d+|) \@\@ .* +^@@ -\d+(?:,\d+|) \+\d+(?:,\d+|) @@ .* # git index header index (?:[0-9a-z]{7,40},|)[0-9a-z]{7,40}\.\.[0-9a-z]{7,40} @@ -27,13 +27,16 @@ index (?:[0-9a-z]{7,40},|)[0-9a-z]{7,40}\.\.[0-9a-z]{7,40} # data url in quotes ([`'"])data:(?:[^ `'"].*?|)(?:[A-Z]{3,}|[A-Z][a-z]{2,}|[a-z]{3,}).*\g{-1} # data url -data:[-a-zA-Z=;:/0-9+]*,\S* +\bdata:[-a-zA-Z=;:/0-9+]*,\S* + +# https/http/file urls +(?:\b(?:https?|ftp|file)://)[-A-Za-z0-9+&@#/*%?=~_|!:,.;]+[-A-Za-z0-9+&@#/*%=~_|] # https/http/file urls (?:\b(?:https?|ftp|file)://)[-A-Za-z0-9+&@#/%?=~_|!:,.;]+[-A-Za-z0-9+&@#/%=~_|] # mailto urls -mailto:[-a-zA-Z=;:/?%&0-9+@.]{3,} +mailto:[-a-zA-Z=;:/?%&0-9+@._]{3,} # magnet urls magnet:[?=:\w]+ @@ -153,6 +156,9 @@ themes\.googleusercontent\.com/static/fonts/[^/\s"]+/v\d+/[^.]+. # GHSA GHSA(?:-[0-9a-z]{4}){3} +# GitHub actions +\buses:\s+[-\w.]+/[-\w./]+@[-\w.]+ + # GitLab commit \bgitlab\.[^/\s"]*/\S+/\S+/commit/[0-9a-f]{7,16}#[0-9a-f]{40}\b # GitLab merge requests @@ -211,7 +217,7 @@ accounts\.binance\.com/[a-z/]*oauth/authorize\?[-0-9a-zA-Z&%]* # medium link \blink\.medium\.com/[a-zA-Z0-9]+ # medium -\bmedium\.com/\@?[^/\s"]+/[-\w]+ +\bmedium\.com/@?[^/\s"]+/[-\w]+ # microsoft \b(?:https?://|)(?:(?:download\.visualstudio|docs|msdn2?|research)\.microsoft|blogs\.msdn)\.com/[-_a-zA-Z0-9()=./%]* @@ -276,7 +282,7 @@ slack://[a-zA-Z0-9?&=]+ [0-9a-f]{32}\@o\d+\.ingest\.sentry\.io\b # Twitter markdown -\[\@[^[/\]:]*?\]\(https://twitter.com/[^/\s"')]*(?:/status/\d+(?:\?[-_0-9a-zA-Z&=]*|)|)\) +\[@[^[/\]:]*?\]\(https://twitter.com/[^/\s"')]*(?:/status/\d+(?:\?[-_0-9a-zA-Z&=]*|)|)\) # Twitter hashtag \btwitter\.com/hashtag/[\w?_=&]* # Twitter status @@ -331,7 +337,7 @@ ipfs://[0-9a-zA-Z]{3,} [^"\s]+/gitweb/\S+;h=[0-9a-f]+ # HyperKitty lists -/archives/list/[^@/]+\@[^/\s"]*/message/[^/\s"]*/ +/archives/list/[^@/]+@[^/\s"]*/message/[^/\s"]*/ # lists /thread\.html/[^"\s]+ @@ -349,7 +355,7 @@ ipfs://[0-9a-zA-Z]{3,} \bopen\.spotify\.com/embed/playlist/\w+ # Mastodon -\bmastodon\.[-a-z.]*/(?:media/|\@)[?&=0-9a-zA-Z_]* +\bmastodon\.[-a-z.]*/(?:media/|@)[?&=0-9a-zA-Z_]* # scastie \bscastie\.scala-lang\.org/[^/]+/\w+ @@ -391,9 +397,9 @@ ipfs://[0-9a-zA-Z]{3,} (?:\\(?:u00|x)1[Bb]|\x1b|\\u\{1[Bb]\})\[\d+(?:;\d+|)m # URL escaped characters -\%[0-9A-F][A-F](?=[A-Za-z]) +%[0-9A-F][A-F](?=[A-Za-z]) # lower URL escaped characters -\%[0-9a-f][a-f](?=[a-z]{2,}) +%[0-9a-f][a-f](?=[a-z]{2,}) # IPv6 #\b(?:[0-9a-fA-F]{0,4}:){3,7}[0-9a-fA-F]{0,4}\b @@ -402,7 +408,7 @@ ipfs://[0-9a-zA-Z]{3,} # Punycode \bxn--[-0-9a-z]+ # sha -sha\d+:[0-9]*[a-f]{3,}[0-9a-f]* +sha\d+:[0-9a-f]*?[a-f]{3,}[0-9a-f]* # sha-... -- uses a fancy capture (\\?['"]|")[0-9a-f]{40,}\g{-1} # hex runs @@ -422,10 +428,13 @@ sha\d+:[0-9]*[a-f]{3,}[0-9a-f]* # pki -----BEGIN.*-----END +# pki (base64) +LS0tLS1CRUdJT.* + # uuid: \b[0-9a-fA-F]{8}-(?:[0-9a-fA-F]{4}-){3}[0-9a-fA-F]{12}\b # hex digits including css/html color classes: -(?:[\\0][xX]|\\u|[uU]\+|#x?|\%23)[0-9_a-fA-FgGrR]*?[a-fA-FgGrR]{2,}[0-9_a-fA-FgGrR]*(?:[uUlL]{0,3}|[iu]\d+)\b +(?:[\\0][xX]|\\u|[uU]\+|#x?|%23)[0-9_a-fA-FgGrR]*?[a-fA-FgGrR]{2,}[0-9_a-fA-FgGrR]*(?:[uUlL]{0,3}|[iu]\d+)\b # integrity integrity=(['"])(?:\s*sha\d+-[-a-zA-Z=;:/0-9+]{40,})+\g{-1} @@ -443,20 +452,47 @@ integrity=(['"])(?:\s*sha\d+-[-a-zA-Z=;:/0-9+]{40,})+\g{-1} Name\[[^\]]+\]=.* # IServiceProvider / isAThing -\b(?:I|isA)(?=(?:[A-Z][a-z]{2,})+\b) +(?:\b|_)(?:(?:ns|)I|isA)(?=(?:[A-Z][a-z]{2,})+(?:[A-Z\d]|\b)) # crypt (['"])\$2[ayb]\$.{56}\g{-1} +# apache/old crypt +#(['"]|)\$+(?:apr|)1\$+.{8}\$+.{22}\g{-1} + +# sha1 hash +\{SHA\}[-a-zA-Z=;:/0-9+]{3,} + +# machine learning (?) +\b(?i)ml(?=[a-z]{2,}) + +# python +\b(?i)py(?!gments|gmy|lon|ramid|ro|th)(?=[a-z]{2,}) + # scrypt / argon \$(?:scrypt|argon\d+[di]*)\$\S+ # go.sum \bh1:\S+ +# scala imports +^import (?:[\w.]|\{\w*?(?:,\s*(?:\w*|\*))+\})+ + # scala modules ("[^"]+"\s*%%?\s*){2,3}"[^"]+" +# container images +image: [-\w./:@]+ + +# Docker images +^\s*FROM\s+\S+:\S+(?:\s+AS\s+\S+|) + +# `docker images` REPOSITORY TAG IMAGE ID CREATED SIZE +\s*\S+/\S+\s+\S+\s+[0-9a-f]{8,}\s+\d+\s+(?:hour|day|week)s ago\s+[\d.]+[KMGT]B + +# Intel intrinsics +_mm_(?!dd)\w+ + # Input to GitHub JSON content: (['"])[-a-zA-Z=;:/0-9+]*=\g{-1} @@ -464,34 +500,43 @@ content: (['"])[-a-zA-Z=;:/0-9+]*=\g{-1} # you'll want to remove the `(?=.*?")` suffix. # The `(?=.*?")` suffix should limit the false positives rate # printf -#%(?:(?:(?:hh?|ll?|[jzt])?[diuoxn]|l?[cs]|L?[fega]|p)(?=[a-z]{2,})|(?:X|L?[FEGA]|p)(?=[a-zA-Z]{2,}))(?=[_a-zA-Z]+\b)(?!%)(?=.*?['"]) +#%(?:(?:(?:hh?|ll?|[jzt])?[diuoxn]|l?[cs]|L?[fega]|p)(?=[a-z]{2,})|(?:X|L?[FEGA])(?=[a-zA-Z]{2,}))(?!%)(?=[_a-zA-Z]+(?!%)\b)(?=.*?['"]) +# Alternative printf +# %s +%(?:s(?=[a-z]{2,}))(?!%)(?=[_a-zA-Z]+(?!%[^s])\b)(?=.*?['"]) # Python string prefix / binary prefix # Note that there's a high false positive rate, remove the `?=` and search for the regex to see if the matches seem like reasonable strings -(?|m([|!/@#,;']).*?\g{-1}) # perl qr regex (?|\(.*?\)|([|!/@#,;']).*?\g{-1}) +# perl run +perl(?:\s+-[a-zA-Z]\w*)+ + +# C network byte conversions +(?:\d|\bh)to(?!ken)(?=[a-z])|to(?=[adhiklpun]\() + # Go regular expressions regexp?\.MustCompile\(`[^`]*`\) @@ -505,14 +550,20 @@ regexp?\.MustCompile\(`[^`]*`\) sed 's/(?:[^/]*?[a-zA-Z]{3,}[^/]*?/){2} # node packages -(["'])\@[^/'" ]+/[^/'" ]+\g{-1} +(["'])@[^/'" ]+/[^/'" ]+\g{-1} # go install go install(?:\s+[a-z]+\.[-@\w/.]+)+ +# pom.xml +<(?:group|artifact)Id>.*?< + # jetbrains schema https://youtrack.jetbrains.com/issue/RSRP-489571 urn:shemas-jetbrains-com +# Debian changelog severity +[-\w]+ \(.*\) (?:\w+|baseline|unstable|experimental); urgency=(?:low|medium|high|emergency|critical)\b + # kubernetes pod status lists # https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/#pod-phase \w+(?:-\w+)+\s+\d+/\d+\s+(?:Running|Pending|Succeeded|Failed|Unknown)\s+ @@ -520,9 +571,15 @@ urn:shemas-jetbrains-com # kubectl - pods in CrashLoopBackOff \w+-[0-9a-f]+-\w+\s+\d+/\d+\s+CrashLoopBackOff\s+ +# kubernetes applications +\.apps/[-\w]+ + # kubernetes object suffix -[0-9a-f]{10}-\w{5}\s +# kubernetes crd patterns +^\s*pattern: .*$ + # posthog secrets ([`'"])phc_[^"',]+\g{-1} @@ -534,6 +591,9 @@ urn:shemas-jetbrains-com # xcode api botches customObjectInstantitationMethod +# msvc api botches +PrependWithABINamepsace + # configure flags .* \| --\w{2,}.*?(?=\w+\s\w+) @@ -541,21 +601,34 @@ customObjectInstantitationMethod \.fa-[-a-z0-9]+ # bearer auth -(['"])Bear[e][r] .*?\g{-1} +(['"])[Bb]ear[e][r] .*?\g{-1} + +# bearer auth +\b[Bb]ear[e][r]:? [-a-zA-Z=;:/0-9+.]+ # basic auth -(['"])Basic [-a-zA-Z=;:/0-9+]{3,}\g{-1} +(['"])[Bb]asic [-a-zA-Z=;:/0-9+]{3,}\g{-1} # base64 encoded content -#([`'"])[-a-zA-Z=;:/0-9+]+=\g{-1} +#([`'"])[-a-zA-Z=;:/0-9+]{3,}=\g{-1} # base64 encoded content in xml/sgml ->[-a-zA-Z=;:/0-9+]+=[-a-zA-Z=;:/0-9+]{3,}== 0.0.22) \\\w{2,}\{ +# American Mathematical Society (AMS) / Doxygen +TeX/AMS + +# File extensions +\*\.[+\w]+, + # eslint "varsIgnorePattern": ".+" +# nolint +nolint:\w+ + # Windows short paths -[/\\][^/\\]{5,6}~\d{1,2}[/\\] +[/\\][^/\\]{5,6}~\d{1,2}(?=[/\\]) + +# cygwin paths +/cygdrive/[a-zA-Z]/(?:Program Files(?: \(.*?\)| ?)(?:/[-+.~\\/()\w ]+)*|[-+.~\\/()\w])+ # in check-spelling@v0.0.22+, printf markers aren't automatically consumed # printf markers #(? Don't use `can not` when you mean `cannot`. The only time you're likely to see `can not` written as separate words is when the word `can` happens to precede some other phrase that happens to start with `not`. +# > `Can't` is a contraction of `cannot`, and it's best suited for informal writing. +# > In formal writing and where contractions are frowned upon, use `cannot`. +# > It is possible to write `can not`, but you generally find it only as part of some other construction, such as `not only . . . but also.` +# - if you encounter such a case, add a pattern for that case to patterns.txt. +\b[Cc]an not\b + +# Do not use `(click) here` links +# For more information, see: +# * https://www.w3.org/QA/Tips/noClickHere +# * https://webaim.org/techniques/hypertext/link_text +# * https://granicus.com/blog/why-click-here-links-are-bad/ +# * https://heyoka.medium.com/dont-use-click-here-f32f445d1021 +(?i)(?:>|\[)(?:(?:click |)here|link|(?:read |)more)(?:)[0-9a-fA-F]{8}-(?:[0-9a-fA-F]{4}-){3}[0-9a-fA-F]{12}(?:[}"]|"'`=(])-(?:D(?=[A-Z])|[WX]|f(?=[ms]))(?=[A-Z]{2,}|[A-Z][a-z]|[a-z]{2,}) +(?:^|[\t ,>"'`=(])-(?:D(?=[A-Z])|W(?!ork)|X|f(?=[ms]))(?=[A-Z]{2,}|[A-Z][a-z]|[a-z]{2,}) # hit-count: 60 file-count: 35 # version suffix v# @@ -133,19 +176,38 @@ mailto:[-a-zA-Z=;:/?%&0-9+@.]{3,} # to opt in \bto opt in\b +# Questionably acceptable forms of `in to` +# Personally, I prefer `log into`, but people object +# https://www.tprteaching.com/log-into-log-in-to-login/ +\b(?:(?:[Ll]og(?:g(?=[a-z])|)|[Ss]ign)(?:ed|ing)?) in to\b + +# to opt in +\bto opt in\b # acceptable duplicates # ls directory listings -[-bcdlpsw](?:[-r][-w][-Ssx]){3}\s+\d+\s+\S+\s+\S+\s+\d+\s+ +[-bcdlpsw](?:[-r][-w][-SsTtx]){3}[\.+*]?\s+\d+\s+\S+\s+\S+\s+[.\d]+(?:[KMGT]|)\s+ # mount \bmount\s+-t\s+(\w+)\s+\g{-1}\b -# C types and repeated CSS values -\s(auto|center|div|Guid|inherit|long|LONG|none|normal|solid|that|thin|transparent|very)(?: \g{-1})+\s -# C struct -\bstruct\s+(\w+)\s+\g{-1}\b +# C/idl types, repeated CSS values, + English ... +\s(auto|buffalo|center|div|Guid|GUID|inherit|long|LONG|none|normal|solid|that|thin|transparent|very)(?: \g{-1})+\s +# C enum and struct +\b(?:enum|struct)\s+(\w+)\s+\g{-1}\b # go templates \s(\w+)\s+\g{-1}\s+\`(?:graphql|inject|json|yaml): # doxygen / javadoc / .net -(?:[\\@](?:brief|groupname|t?param|return|retval)|(?:public|private|\[Parameter(?:\(.+\)|)\])(?:\s+static|\s+override|\s+readonly)*)(?:\s+\{\w+\}|)\s+(\w+)\s+\g{-1}\s +(?:[\\@](?:brief|defgroup|groupname|link|t?param|return|retval)|(?:public|private|\[Parameter(?:\(.+\)|)\])(?:\s+(?:static|override|readonly|required|virtual))*)(?:\s+\{\w+\}|)\s+(\w+)\s+\g{-1}\s + +# macOS file path +(?:Contents\W+|(?!iOS)/)MacOS\b + +# Python package registry has incorrect spelling for macOS / Mac OS X +"Operating System :: MacOS :: MacOS X" + +# "company" in Germany +\bGmbH\b + +# IntelliJ +\bIntelliJ\b # Commit message -- Signed-off-by and friends ^\s*(?:(?:Based-on-patch|Co-authored|Helped|Mentored|Reported|Reviewed|Signed-off)-by|Thanks-to): (?:[^<]*<[^>]*>|[^<]*)\s*$ diff --git a/.github/actions/spelling/reject.txt b/.github/actions/spelling/reject.txt index 2ac1670d53..d98038f96f 100644 --- a/.github/actions/spelling/reject.txt +++ b/.github/actions/spelling/reject.txt @@ -5,9 +5,11 @@ benefitting occurences? ^dependan.* +^diables?$ ^oer$ Sorce ^[Ss]pae.* +^Teh$ ^untill$ ^untilling$ ^wether.* diff --git a/.github/policies/resourceManagement.yml b/.github/policies/resourceManagement.yml index 695df7162d..7bdd1b5d03 100644 --- a/.github/policies/resourceManagement.yml +++ b/.github/policies/resourceManagement.yml @@ -8,7 +8,7 @@ where: configuration: resourceManagementConfiguration: scheduledSearches: - - description: + - description: '"Needs-Author-Feedback" and "No-Recent-Activity" issues are closed after 3 days of inactivity' frequencies: - hourly: hour: 3 @@ -23,7 +23,7 @@ configuration: days: 3 actions: - closeIssue - - description: + - description: '"Needs-Author-Feedback" issues are labelled "No-Recent-Activity" after 4 days of inactivity' frequencies: - hourly: hour: 3 @@ -41,7 +41,7 @@ configuration: label: No-Recent-Activity - addReply: reply: This issue has been automatically marked as stale because it has been marked as requiring author feedback but has not had any activity for **4 days**. It will be closed if no further activity occurs **within 3 days of this comment**. - - description: + - description: '"Resolution-Duplicate" issues are closed after 1 day of inactivity' frequencies: - hourly: hour: 3 @@ -56,7 +56,7 @@ configuration: - addReply: reply: This issue has been marked as duplicate and has not had any activity for **1 day**. It will be closed for housekeeping purposes. - closeIssue - - description: + - description: '"Needs-Author-Feedback" and "No-Recent-Activity" PRs are closed after 7 days of inactivity' frequencies: - hourly: hour: 3 @@ -71,7 +71,7 @@ configuration: days: 7 actions: - closeIssue - - description: + - description: Add "No-Recent-Activity" label to PRs with "Needs-Author-Feedback" label after 7 days of inactivity frequencies: - hourly: hour: 3 @@ -90,7 +90,8 @@ configuration: - addReply: reply: This pull request has been automatically marked as stale because it has been marked as requiring author feedback but has not had any activity for **7 days**. It will be closed if no further activity occurs **within 7 days of this comment**. eventResponderTasks: - - if: + - description: Add "Needs-Triage" to new issues + if: - payloadType: Issues - or: - and: @@ -102,8 +103,8 @@ configuration: then: - addLabel: label: Needs-Triage - description: - - if: + - description: Replace "Needs-Author-Feedback" with "Needs-Attention" when author comments + if: - payloadType: Issue_Comment - isAction: action: Created @@ -116,8 +117,8 @@ configuration: label: Needs-Attention - removeLabel: label: Needs-Author-Feedback - description: - - if: + - description: Remove "No-Recent-Activity" when closing an issue + if: - payloadType: Issues - not: isAction: @@ -127,16 +128,16 @@ configuration: then: - removeLabel: label: No-Recent-Activity - description: - - if: + - description: Remove "No-Recent-Activity" when someone comments on an issue + if: - payloadType: Issue_Comment - hasLabel: label: No-Recent-Activity then: - removeLabel: label: No-Recent-Activity - description: - - if: + - description: Add "Needs-Author-Feedback" when changes are requested on a PR + if: - payloadType: Pull_Request_Review - isAction: action: Submitted @@ -145,8 +146,8 @@ configuration: then: - addLabel: label: Needs-Author-Feedback - description: - - if: + - description: Remove "Needs-Author-Feedback" when author performs activity on their PR + if: - payloadType: Pull_Request - isActivitySender: issueAuthor: True @@ -158,8 +159,8 @@ configuration: then: - removeLabel: label: Needs-Author-Feedback - description: - - if: + - description: Remove "Needs-Author-Feedback" when author comments on their issue + if: - payloadType: Issue_Comment - isActivitySender: issueAuthor: True @@ -168,8 +169,8 @@ configuration: then: - removeLabel: label: Needs-Author-Feedback - description: - - if: + - description: Remove "Needs-Author-Feedback" when the author reviews the PR + if: - payloadType: Pull_Request_Review - isActivitySender: issueAuthor: True @@ -178,8 +179,8 @@ configuration: then: - removeLabel: label: Needs-Author-Feedback - description: - - if: + - description: Remove "No-Recent-Activity"" when activity occurs on the PR (aside from closing it) + if: - payloadType: Pull_Request - not: isAction: @@ -189,39 +190,39 @@ configuration: then: - removeLabel: label: No-Recent-Activity - description: - - if: + - description: Remove "No-Recent-Activity" when someone comments on the PR + if: - payloadType: Issue_Comment - hasLabel: label: No-Recent-Activity then: - removeLabel: label: No-Recent-Activity - description: - - if: + - description: Remove "No-Recent-Activity" when someone reviews the PR + if: - payloadType: Pull_Request_Review - hasLabel: label: No-Recent-Activity then: - removeLabel: label: No-Recent-Activity - description: - - if: + - description: Enable auto-merge on PRs with the "AutoMerge" label + if: - payloadType: Pull_Request - hasLabel: label: AutoMerge then: - enableAutoMerge: mergeMethod: Squash - description: - - if: + - description: Disable auto-merge on PRs when the "AutoMerge" label is removed + if: - payloadType: Pull_Request - labelRemoved: label: AutoMerge then: - disableAutoMerge - description: - - if: + - description: Add "Needs-Tag-Fix" label to issues without an Area, Issue, or Product label + if: - payloadType: Issues - or: - and: @@ -238,15 +239,45 @@ configuration: - not: hasLabel: label: Area-Accessibility + - not: + hasLabel: + label: Area-AtlasEngine + - not: + hasLabel: + label: Area-AzureShell - not: hasLabel: label: Area-Build + - not: + hasLabel: + label: Area-Chat + - not: + hasLabel: + label: Area-CmdPal + - not: + hasLabel: + label: Area-CodeHealth + - not: + hasLabel: + label: Area-Commandline + - not: + hasLabel: + label: Area-CookedRead + - not: + hasLabel: + label: Area-DefApp - not: hasLabel: label: Area-Extensibility - not: hasLabel: label: Area-Fonts + - not: + hasLabel: + label: Area-GroupPolicy + - not: + hasLabel: + label: Area-i18n - not: hasLabel: label: Area-Input @@ -256,21 +287,45 @@ configuration: - not: hasLabel: label: Area-Interop + - not: + hasLabel: + label: Area-Localization - not: hasLabel: label: Area-Output - not: hasLabel: label: Area-Performance + - not: + hasLabel: + label: Area-Portable + - not: + hasLabel: + label: Area-Quality + - not: + hasLabel: + label: Area-Remoting - not: hasLabel: label: Area-Rendering + - not: + hasLabel: + label: Area-Schema - not: hasLabel: label: Area-Server - not: hasLabel: label: Area-Settings + - not: + hasLabel: + label: Area-SettingsUI + - not: + hasLabel: + label: Area-ShellExtension + - not: + hasLabel: + label: Area-Suggestions - not: hasLabel: label: Area-TerminalConnection @@ -279,49 +334,19 @@ configuration: label: Area-TerminalControl - not: hasLabel: - label: Area-User Interface + label: Area-Theming + - not: + hasLabel: + label: Area-UserInterface - not: hasLabel: label: Area-VT - - not: - hasLabel: - label: Area-CodeHealth - - not: - hasLabel: - label: Area-Quality - - not: - hasLabel: - label: Area-AzureShell - - not: - hasLabel: - label: Area-Schema - - not: - hasLabel: - label: Area-Commandline - - not: - hasLabel: - label: Area-ShellExtension - - not: - hasLabel: - label: Area-WPFControl - - not: - hasLabel: - label: Area-Settings UI - - not: - hasLabel: - label: Area-DefApp - - not: - hasLabel: - label: Area-Remoting - not: hasLabel: label: Area-Windowing - not: hasLabel: - label: Area-Theming - - not: - hasLabel: - label: Area-Localization + label: Area-WPFControl - and: - not: hasLabel: @@ -408,8 +433,8 @@ configuration: then: - addLabel: label: Needs-Tag-Fix - description: - - if: + - description: Remove "Needs-Tag-Fix" label when an issue is tagged with an Area, Issue, and Product label + if: - payloadType: Issues - and: - isLabeled @@ -417,66 +442,117 @@ configuration: label: Needs-Tag-Fix - and: - or: - - hasLabel: - label: Area-Accessibility - - hasLabel: - label: Area-Build - - hasLabel: - label: Area-Extensibility - - hasLabel: - label: Area-Fonts - - hasLabel: - label: Area-Input - - hasLabel: - label: Area-Interaction - - hasLabel: - label: Area-Interop - - hasLabel: - label: Area-Output - - hasLabel: - label: Area-Performance - - hasLabel: - label: Area-Rendering - - hasLabel: - label: Area-Server - - hasLabel: - label: Area-Settings - - hasLabel: - label: Area-TerminalConnection - - hasLabel: - label: Area-TerminalControl - - hasLabel: - label: Area-User Interface - - hasLabel: - label: Area-VT - - hasLabel: - label: Area-CodeHealth - - hasLabel: - label: Area-Quality - - hasLabel: - label: Area-Schema - - hasLabel: - label: Area-AzureShell - - hasLabel: - label: Area-Commandline - - hasLabel: - label: Area-ShellExtension - - hasLabel: - label: Area-WPFControl - - hasLabel: - label: Area-Settings UI - - hasLabel: - label: Area-DefApp - - hasLabel: - label: Area-Localization - - hasLabel: - label: Area-Windowing - - hasLabel: - label: Area-Theming - - hasLabel: - label: Area-AtlasEngine - - hasLabel: - label: Area-CmdPal + - not: + hasLabel: + label: Area-Accessibility + - not: + hasLabel: + label: Area-AtlasEngine + - not: + hasLabel: + label: Area-AzureShell + - not: + hasLabel: + label: Area-Build + - not: + hasLabel: + label: Area-Chat + - not: + hasLabel: + label: Area-CmdPal + - not: + hasLabel: + label: Area-CodeHealth + - not: + hasLabel: + label: Area-Commandline + - not: + hasLabel: + label: Area-CookedRead + - not: + hasLabel: + label: Area-DefApp + - not: + hasLabel: + label: Area-Extensibility + - not: + hasLabel: + label: Area-Fonts + - not: + hasLabel: + label: Area-GroupPolicy + - not: + hasLabel: + label: Area-i18n + - not: + hasLabel: + label: Area-Input + - not: + hasLabel: + label: Area-Interaction + - not: + hasLabel: + label: Area-Interop + - not: + hasLabel: + label: Area-Localization + - not: + hasLabel: + label: Area-Output + - not: + hasLabel: + label: Area-Performance + - not: + hasLabel: + label: Area-Portable + - not: + hasLabel: + label: Area-Quality + - not: + hasLabel: + label: Area-Remoting + - not: + hasLabel: + label: Area-Rendering + - not: + hasLabel: + label: Area-Schema + - not: + hasLabel: + label: Area-Server + - not: + hasLabel: + label: Area-Settings + - not: + hasLabel: + label: Area-SettingsUI + - not: + hasLabel: + label: Area-ShellExtension + - not: + hasLabel: + label: Area-Suggestions + - not: + hasLabel: + label: Area-TerminalConnection + - not: + hasLabel: + label: Area-TerminalControl + - not: + hasLabel: + label: Area-Theming + - not: + hasLabel: + label: Area-UserInterface + - not: + hasLabel: + label: Area-VT + - not: + hasLabel: + label: Area-Windowing + - not: + hasLabel: + label: Area-WPFControl - or: - hasLabel: label: Issue-Bug @@ -533,14 +609,14 @@ configuration: then: - removeLabel: label: Needs-Tag-Fix - description: - - if: + - description: Add "In-PR" label to issues that are referenced in a PR + if: - payloadType: Pull_Request then: - inPrLabel: label: In-PR - description: - - if: + - description: Remove "Needs-Tag-Fix" label when an issue also has the "Resolution-Duplicate" label + if: - payloadType: Issues - hasLabel: label: Needs-Tag-Fix @@ -549,8 +625,8 @@ configuration: then: - removeLabel: label: Needs-Tag-Fix - description: - - if: + - description: Close issues that are opened and have the template title + if: - payloadType: Issues - or: - titleContains: @@ -576,8 +652,8 @@ configuration: label: Needs-Author-Feedback - addReply: reply: Hi! Thanks for attempting to open an issue. Unfortunately, your title wasn't changed from the original template which makes it very hard for us to track and triage. You are welcome to fix up the title and try again with a new issue. - description: - - if: + - description: Close issues that are opened and have no body + if: - payloadType: Issues - or: - isAction: @@ -595,8 +671,8 @@ configuration: label: Needs-Author-Feedback - addReply: reply: "Hi! Thanks for attempting to open an issue. Unfortunately, you didn't write anything in the body which makes it impossible to understand your concern. You are welcome to fix up the issue and try again by opening another issue with the body filled out. " - description: - - if: + - description: Request a review from the team when a PR is labeled "Needs-Second" + if: - payloadType: Pull_Request - isLabeled - hasLabel: @@ -613,8 +689,8 @@ configuration: reviewer: dhowett - requestReview: reviewer: lhecker - description: - - if: + - description: Remove "Needs-Second" label when a PR is reviewed + if: - payloadType: Pull_Request_Review - not: isOpen - hasLabel: @@ -622,8 +698,8 @@ configuration: then: - removeLabel: label: Needs-Second - description: - - if: + - description: Remove "Help-Wanted" label from issues that are in a PR + if: - payloadType: Issues - hasLabel: label: In-PR @@ -633,8 +709,8 @@ configuration: then: - removeLabel: label: Help-Wanted - description: - - if: + - description: Comments with "/dup", "/dupe", or "/duplicate" will close the issue as a duplicate and remove "Needs-" labels + if: - payloadType: Issue_Comment - commentContains: pattern: '\/dup(licate|e)?(\s+of)?\s+\#[\d]+' @@ -662,8 +738,8 @@ configuration: label: Needs-Repro - removeLabel: label: Needs-Second - description: - - if: + - description: Comments with "/feedback" will direct people to Feedback Hub + if: - payloadType: Issue_Comment - commentContains: pattern: '\/feedback' @@ -680,13 +756,13 @@ configuration: Hi there!

Can you please send us feedback with the [Feedback Hub](https://support.microsoft.com/en-us/windows/send-feedback-to-microsoft-with-the-feedback-hub-app-f59187f8-8739-22d6-ba93-f66612949332) with this issue? Make sure to click the "Start recording" button, then reproduce the issue before submitting the feedback. Once it's submitted, paste the link here so we can more easily find your crash information on the back end?

Thanks!

![image](https://user-images.githubusercontent.com/18356694/140811502-a068f78b-89d2-4587-925a-73e19652b830.png)

![image](https://user-images.githubusercontent.com/18356694/140811557-cdc22a0f-fa6a-4f6a-953e-73b51f5548a3.png)

![image](https://user-images.githubusercontent.com/18221333/62478649-6de55400-b760-11e9-806e-5aab7e085a9f.png) - addLabel: label: Needs-Author-Feedback - description: - - if: + - description: Comments clean the email reply + if: - payloadType: Issue_Comment then: - cleanEmailReply - description: - - if: + - description: Sync labels when a PR event occurs + if: - payloadType: Pull_Request then: - labelSync: @@ -701,8 +777,8 @@ configuration: pattern: Severity- - labelSync: pattern: Impact- - description: - - if: + - description: Comments with "/dup", "/dupe", or "/duplicate" targeting another repo will close the issue as a duplicate and remove "Needs-" labels + if: - payloadType: Issue_Comment - commentContains: pattern: '\/dup(licate|e)?(\s+of)?\s+https' @@ -730,8 +806,8 @@ configuration: label: Needs-Repro - removeLabel: label: Needs-Second - description: - - if: + - description: Comments with "/?" will replace the "Needs-Attention" label with "Needs-Author-Feedback" + if: - payloadType: Issue_Comment - commentContains: pattern: /? @@ -746,6 +822,5 @@ configuration: label: Needs-Attention - addLabel: label: Needs-Author-Feedback - description: onFailure: onSuccess: diff --git a/.github/workflows/addToProject.yml b/.github/workflows/addToProject.yml index e756dec59d..c8a5c68326 100644 --- a/.github/workflows/addToProject.yml +++ b/.github/workflows/addToProject.yml @@ -13,7 +13,7 @@ jobs: name: Add issue to project runs-on: ubuntu-latest steps: - - uses: actions/add-to-project@v1.0.1 + - uses: actions/add-to-project@v1.0.2 with: project-url: https://github.com/orgs/microsoft/projects/159 github-token: ${{ secrets.ADD_TO_PROJECT_PAT }} diff --git a/.github/workflows/similarIssues.yml b/.github/workflows/similarIssues.yml deleted file mode 100644 index 290f83cbdc..0000000000 --- a/.github/workflows/similarIssues.yml +++ /dev/null @@ -1,33 +0,0 @@ -name: GitGudSimilarIssues comments - -on: - issues: - types: [opened] - -jobs: - getSimilarIssues: - runs-on: ubuntu-latest - outputs: - message: ${{ steps.getBody.outputs.message }} - steps: - - id: getBody - uses: craigloewen-msft/GitGudSimilarIssues@main - with: - issueTitle: ${{ github.event.issue.title }} - issueBody: ${{ github.event.issue.body }} - repo: ${{ github.repository }} - similaritytolerance: "0.8" - add-comment: - needs: getSimilarIssues - runs-on: ubuntu-latest - permissions: - issues: write - if: needs.getSimilarIssues.outputs.message != '' - steps: - - name: Add comment - run: gh issue comment "$NUMBER" --repo "$REPO" --body "$BODY" - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - NUMBER: ${{ github.event.issue.number }} - REPO: ${{ github.repository }} - BODY: ${{ needs.getSimilarIssues.outputs.message }} diff --git a/.github/workflows/spelling2.yml b/.github/workflows/spelling2.yml index 2778a7e9e5..7675d5d004 100644 --- a/.github/workflows/spelling2.yml +++ b/.github/workflows/spelling2.yml @@ -34,14 +34,14 @@ name: Spell checking # # For background, see: https://github.com/check-spelling/check-spelling/wiki/Feature:-Update-with-deploy-key -# Sarif reporting +# SARIF reporting # -# Access to Sarif reports is generally restricted (by GitHub) to members of the repository. +# Access to SARIF reports is generally restricted (by GitHub) to members of the repository. # # Requires enabling `security-events: write` # and configuring the action with `use_sarif: 1` # -# For information on the feature, see: https://github.com/check-spelling/check-spelling/wiki/Feature:-Sarif-output +# For information on the feature, see: https://github.com/check-spelling/check-spelling/wiki/Feature:-SARIF-output # Minimal workflow structure: # @@ -60,23 +60,23 @@ name: Spell checking on: push: branches: - - "**" + - "**" tags-ignore: - - "**" + - "**" pull_request_target: branches: - - "**" + - "**" types: - - 'opened' - - 'reopened' - - 'synchronize' + - "opened" + - "reopened" + - "synchronize" issue_comment: types: - - 'created' + - "created" jobs: spelling: - name: Spell checking + name: Check Spelling permissions: contents: read pull-requests: read @@ -91,52 +91,57 @@ jobs: # note: If you use only_check_changed_files, you do not want cancel-in-progress cancel-in-progress: true steps: - - name: check-spelling - id: spelling - uses: check-spelling/check-spelling@v0.0.22 - with: - suppress_push_for_open_pull_request: ${{ github.actor != 'dependabot[bot]' && 1 }} - checkout: true - check_file_names: 1 - spell_check_this: microsoft/terminal@main - post_comment: 0 - use_magic_file: 1 - report-timing: 1 - warnings: bad-regex,binary-file,deprecated-feature,ignored-expect-variant,large-file,limited-references,no-newline-at-eof,noisy-file,non-alpha-in-dictionary,token-is-substring,unexpected-line-ending,whitespace-in-dictionary,minified-file,unsupported-configuration,no-files-to-check - experimental_apply_changes_via_bot: ${{ github.repository_owner != 'microsoft' && 1 }} - use_sarif: ${{ (!github.event.pull_request || (github.event.pull_request.head.repo.full_name == github.repository)) && 1 }} - extra_dictionary_limit: 20 - extra_dictionaries: - cspell:software-terms/dict/softwareTerms.txt - cspell:cpp/src/stdlib-cpp.txt - cspell:lorem-ipsum/dictionary.txt - cspell:cpp/src/stdlib-c.txt - cspell:php/dict/php.txt - cspell:filetypes/filetypes.txt - cspell:java/src/java.txt - cspell:python/src/common/extra.txt - cspell:node/dict/node.txt - cspell:java/src/java-terms.txt - cspell:aws/aws.txt - cspell:typescript/dict/typescript.txt - cspell:dotnet/dict/dotnet.txt - cspell:golang/dict/go.txt - cspell:fullstack/dict/fullstack.txt - cspell:cpp/src/compiler-msvc.txt - cspell:python/src/python/python-lib.txt - cspell:mnemonics/src/mnemonics.txt - cspell:cpp/src/stdlib-cmath.txt - cspell:css/dict/css.txt - cspell:cpp/src/lang-keywords.txt - cspell:django/dict/django.txt - cspell:python/src/python/python.txt - cspell:html/dict/html.txt - cspell:cpp/src/ecosystem.txt - cspell:cpp/src/compiler-clang-attributes.txt - cspell:npm/dict/npm.txt - cspell:r/src/r.txt - cspell:powershell/dict/powershell.txt - cspell:csharp/csharp.txt + - name: check-spelling + id: spelling + uses: check-spelling/check-spelling@v0.0.24 + with: + suppress_push_for_open_pull_request: ${{ github.actor != 'dependabot[bot]' && 1 }} + checkout: true + check_file_names: 1 + spell_check_this: microsoft/terminal@main + post_comment: 0 + use_magic_file: 1 + report-timing: 1 + warnings: bad-regex,binary-file,deprecated-feature,ignored-expect-variant,large-file,limited-references,no-newline-at-eof,noisy-file,non-alpha-in-dictionary,token-is-substring,unexpected-line-ending,whitespace-in-dictionary,minified-file,unsupported-configuration,no-files-to-check,unclosed-block-ignore-begin,unclosed-block-ignore-end + experimental_apply_changes_via_bot: ${{ github.repository_owner != 'microsoft' && 1 }} + use_sarif: ${{ (!github.event.pull_request || (github.event.pull_request.head.repo.full_name == github.repository)) && 1 }} + check_extra_dictionaries: "" + dictionary_source_prefixes: > + { + "cspell": "https://raw.githubusercontent.com/check-spelling/cspell-dicts/v20241114/dictionaries/" + } + extra_dictionaries: | + cspell:software-terms/softwareTerms.txt + cspell:cpp/stdlib-cpp.txt + cspell:cpp/stdlib-c.txt + cspell:lorem-ipsum/dictionary.txt + cspell:php/php.txt + cspell:filetypes/filetypes.txt + cspell:java/java.txt + cspell:node/node.txt + cspell:golang/go.txt + cspell:java/java-terms.txt + cspell:mnemonics/mnemonics.txt + cspell:npm/npm.txt + cspell:fullstack/fullstack.txt + cspell:python/python/python-lib.txt + cspell:dotnet/dotnet.txt + cspell:dart/dart.txt + cspell:aws/aws.txt + cspell:python/common/extra.txt + cspell:css/css.txt + cspell:cpp/stdlib-cmath.txt + cspell:typescript/typescript.txt + cspell:cpp/compiler-msvc.txt + cspell:django/django.txt + cspell:html/html.txt + cspell:cpp/lang-keywords.txt + cspell:cpp/ecosystem.txt + cspell:r/r.txt + cspell:cpp/compiler-clang-attributes.txt + cspell:powershell/powershell.txt + cspell:csharp/csharp.txt + cspell:python/python/python.txt comment-push: name: Report (Push) @@ -144,15 +149,16 @@ jobs: runs-on: ubuntu-latest needs: spelling permissions: + actions: read contents: write if: (success() || failure()) && needs.spelling.outputs.followup && github.event_name == 'push' steps: - - name: comment - uses: check-spelling/check-spelling@v0.0.22 - with: - checkout: true - spell_check_this: microsoft/terminal@main - task: ${{ needs.spelling.outputs.followup }} + - name: comment + uses: check-spelling/check-spelling@v0.0.24 + with: + checkout: true + spell_check_this: microsoft/terminal@main + task: ${{ needs.spelling.outputs.followup }} comment-pr: name: Report (PR) @@ -160,17 +166,18 @@ jobs: runs-on: ubuntu-latest needs: spelling permissions: + actions: read contents: read pull-requests: write if: (success() || failure()) && needs.spelling.outputs.followup && contains(github.event_name, 'pull_request') steps: - - name: comment - uses: check-spelling/check-spelling@v0.0.22 - with: - checkout: true - spell_check_this: microsoft/terminal@main - task: ${{ needs.spelling.outputs.followup }} - experimental_apply_changes_via_bot: ${{ github.repository_owner != 'microsoft' && 1 }} + - name: comment + uses: check-spelling/check-spelling@v0.0.24 + with: + checkout: true + spell_check_this: microsoft/terminal@main + task: ${{ needs.spelling.outputs.followup }} + experimental_apply_changes_via_bot: ${{ github.repository_owner != 'microsoft' && 1 }} update: name: Update PR @@ -180,18 +187,19 @@ jobs: actions: read runs-on: ubuntu-latest if: ${{ - github.repository_owner != 'microsoft' && - github.event_name == 'issue_comment' && - github.event.issue.pull_request && - contains(github.event.comment.body, '@check-spelling-bot apply') + github.repository_owner != 'microsoft' && + github.event_name == 'issue_comment' && + github.event.issue.pull_request && + contains(github.event.comment.body, '@check-spelling-bot apply') && + contains(github.event.comment.body, 'https://') }} concurrency: group: spelling-update-${{ github.event.issue.number }} cancel-in-progress: false steps: - - name: apply spelling updates - uses: check-spelling/check-spelling@v0.0.22 - with: - experimental_apply_changes_via_bot: ${{ github.repository_owner != 'microsoft' && 1 }} - checkout: true - ssh_key: "${{ secrets.CHECK_SPELLING }}" + - name: apply spelling updates + uses: check-spelling/check-spelling@v0.0.24 + with: + experimental_apply_changes_via_bot: ${{ github.repository_owner != 'microsoft' && 1 }} + checkout: true + ssh_key: "${{ secrets.CHECK_SPELLING }}" diff --git a/.github/workflows/winget.yml b/.github/workflows/winget.yml index 63464ea4fe..5dda1dc89c 100644 --- a/.github/workflows/winget.yml +++ b/.github/workflows/winget.yml @@ -6,6 +6,9 @@ on: env: REGEX: 'Microsoft\.WindowsTerminal(?:Preview)?_([\d.]+)_8wekyb3d8bbwe\.msixbundle$' + # winget-create will read the following environment variable to access the GitHub token needed for submitting a PR + # See https://aka.ms/winget-create-token + WINGET_CREATE_GITHUB_TOKEN: ${{ secrets.WINGET_TOKEN }} jobs: publish: @@ -21,4 +24,4 @@ jobs: $wingetPackage = "Microsoft.WindowsTerminal${{ github.event.release.prerelease && '.Preview' || '' }}" & curl.exe -JLO https://aka.ms/wingetcreate/latest - & .\wingetcreate.exe update $wingetPackage -s -v $version -u $wingetRelevantAsset.browser_download_url -t "${{ secrets.WINGET_TOKEN }}" + & .\wingetcreate.exe update $wingetPackage -s -v $version -u $wingetRelevantAsset.browser_download_url diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index 94c5e25962..0000000000 --- a/.gitmodules +++ /dev/null @@ -1,3 +0,0 @@ -[submodule "dep/gsl"] - path = dep/gsl - url = https://github.com/microsoft/gsl diff --git a/.vsconfig b/.vsconfig index 505228514f..4d39a491cc 100644 --- a/.vsconfig +++ b/.vsconfig @@ -1,35 +1,51 @@ { "version": "1.0", "components": [ + "Microsoft.VisualStudio.Component.Roslyn.Compiler", + "Microsoft.Component.MSBuild", + "Microsoft.VisualStudio.Component.Roslyn.LanguageServices", + "Microsoft.VisualStudio.Component.SQL.LocalDB.Runtime", + "Microsoft.VisualStudio.Component.SQL.CLR", "Microsoft.VisualStudio.Component.CoreEditor", "Microsoft.VisualStudio.Workload.CoreEditor", - "Microsoft.VisualStudio.Workload.Universal", - "Microsoft.VisualStudio.Workload.NativeDesktop", - "Microsoft.VisualStudio.Workload.ManagedDesktop", - "Microsoft.VisualStudio.Component.ManagedDesktop.Prerequisites", + "Microsoft.Net.Component.4.8.SDK", + "Microsoft.Net.Component.4.7.2.TargetingPack", + "Microsoft.VisualStudio.Component.TextTemplating", "Microsoft.VisualStudio.Component.NuGet", - "Microsoft.VisualStudio.Component.Roslyn.Compiler", - "Microsoft.VisualStudio.Component.Roslyn.LanguageServices", - "Microsoft.Net.ComponentGroup.DevelopmentPrerequisites", - "Microsoft.Component.MSBuild", - "Microsoft.VisualStudio.Component.ManagedDesktop.Core", - "Microsoft.Net.Component.4.TargetingPack", - "Microsoft.Net.Component.4.5.TargetingPack", + "Microsoft.NetCore.Component.Runtime.8.0", + "Microsoft.NetCore.Component.SDK", + "Microsoft.VisualStudio.Component.AppInsights.Tools", + "Microsoft.Net.Component.4.8.TargetingPack", "Microsoft.VisualStudio.Component.DiagnosticTools", - "Microsoft.VisualStudio.Component.Debugger.JustInTime", - "Microsoft.VisualStudio.Component.Windows11SDK.22621", - "Microsoft.VisualStudio.ComponentGroup.UWP.Support", + "Microsoft.NetCore.Component.Runtime.6.0", + "Microsoft.VisualStudio.Component.ClassDesigner", + "Microsoft.VisualStudio.Component.GraphDocument", + "Microsoft.VisualStudio.Component.CodeMap", "Microsoft.VisualStudio.Component.VC.CoreIde", - "Microsoft.VisualStudio.ComponentGroup.NativeDesktop.Core", - "Microsoft.VisualStudio.Component.Graphics", - "Microsoft.VisualStudio.Component.VC.Redist.14.Latest", "Microsoft.VisualStudio.Component.VC.Tools.x86.x64", + "Microsoft.VisualStudio.Component.Windows11SDK.22621", + "Microsoft.VisualStudio.ComponentGroup.MSIX.Packaging", + "Microsoft.VisualStudio.ComponentGroup.WindowsAppSDK.Cs", + "Microsoft.ComponentGroup.Blend", + "Microsoft.VisualStudio.ComponentGroup.ArchitectureTools.Native", + "Microsoft.VisualStudio.Component.VC.Redist.14.Latest", + "Microsoft.VisualStudio.ComponentGroup.NativeDesktop.Core", + "Microsoft.VisualStudio.ComponentGroup.WebToolsExtensions.CMake", + "Microsoft.VisualStudio.Component.Vcpkg", + "Microsoft.Component.NetFX.Native", + "Microsoft.VisualStudio.Component.Graphics", + "Microsoft.VisualStudio.ComponentGroup.UWP.Xamarin", + "Microsoft.VisualStudio.ComponentGroup.UWP.Support", + "Microsoft.VisualStudio.Component.VC.Tools.ARM64EC", + "Microsoft.VisualStudio.Component.UWP.VC.ARM64EC", "Microsoft.VisualStudio.Component.VC.Tools.ARM64", - "Microsoft.VisualStudio.Component.VC.ASAN", - "Microsoft.VisualStudio.Component.VC.v143.x86.x64", - "Microsoft.VisualStudio.Component.VC.v143.ARM64", + "Microsoft.VisualStudio.Component.UWP.VC.ARM64", + "Microsoft.VisualStudio.Component.VC.Tools.ARM", "Microsoft.VisualStudio.ComponentGroup.UWP.VC", - "Microsoft.VisualStudio.ComponentGroup.UWP.VC.v143", - "Microsoft.VisualStudio.Component.UWP.VC.ARM64" - ] + "Microsoft.VisualStudio.Workload.NativeDesktop", + "Microsoft.VisualStudio.ComponentGroup.WindowsAppDevelopment.Prerequisites", + "Microsoft.VisualStudio.ComponentGroup.UWP.NetCoreAndStandard", + "Microsoft.VisualStudio.Workload.Universal" + ], + "extensions": [] } diff --git a/.wt.json b/.wt.json new file mode 100644 index 0000000000..f0091b5e32 --- /dev/null +++ b/.wt.json @@ -0,0 +1,34 @@ +{ + "$version": "1.0.0", + "snippets": + [ + { + "input": "bx\r", + "name": "Build project", + "description": "Build the project in the CWD" + }, + { + "input": "bz\r", + "name": "Build solution, incremental", + "description": "Just build changes to the solution" + }, + { + "input": "bcz\r", + "name": "Clean & build solution", + "icon": "\uE8e6", + "description": "Start over. Go get your coffee. " + }, + { + "input": "nuget push -ApiKey az -source TerminalDependencies %userprofile%\\Downloads", + "name": "Upload package to nuget feed", + "icon": "\uE898", + "description": "Go download a .nupkg, put it in ~/Downloads, and use this to push to our private feed." + }, + { + "input": "runut /name:**\u001b[D", + "name": "Run a test", + "icon": "", + "description": "Enter the name of a test to run" + } + ] +} diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 18ebdd9601..76b68a08d4 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -158,7 +158,7 @@ Once you've discussed your proposed feature/fix/etc. with a team member, and you ### Testing -Testing is a key component in the development workflow. Both Windows Terminal and Windows Console use TAEF(the Test Authoring and Execution Framework) as the main framework for testing. +Testing is a key component in the development workflow. Both Windows Terminal and Windows Console use TAEF (the Test Authoring and Execution Framework) as the main framework for testing. If your changes affect existing test cases, or you're working on brand new features and also the accompanying test cases, see [TAEF](./doc/TAEF.md) for more information about how to validate your work locally. diff --git a/Directory.Build.props b/Directory.Build.props index 312ae503ed..03de869805 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -41,6 +41,11 @@ --> $(MSBuildCacheIdenticalDuplicateOutputPatterns);bin\** + + $(MSBuildCacheIdenticalDuplicateOutputPatterns);obj\*\vcpkg\** + $(MSBuildThisFileDirectory)\dep\nuget\packages.config $(MSBuildCacheIgnoredInputPatterns);$(PackagesConfigFile) diff --git a/NOTICE.md b/NOTICE.md index 091060db2c..efe962bc0d 100644 --- a/NOTICE.md +++ b/NOTICE.md @@ -84,71 +84,6 @@ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ``` -## kimwalisch/libpopcnt - -**Source**: [https://github.com/kimwalisch/libpopcnt](https://github.com/kimwalisch/libpopcnt) - -### License - -``` -BSD 2-Clause License - -Copyright (c) 2016 - 2019, Kim Walisch -Copyright (c) 2016 - 2019, Wojciech Muła - -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -1. Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. -2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -``` - -## dynamic_bitset - -**Source**: [https://github.com/pinam45/dynamic_bitset](https://github.com/pinam45/dynamic_bitset) - -### License - -``` -MIT License - -Copyright (c) 2019 Maxime Pinard - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. -``` - ## \{fmt\} **Source**: [https://github.com/fmtlib/fmt](https://github.com/fmtlib/fmt) @@ -346,6 +281,213 @@ CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ``` +## cmark +**Source**: [https://github.com/commonmark/cmark](https://github.com/commonmark/cmark) + +### License + +``` +Copyright (c) 2014, John MacFarlane + +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +----- + +houdini.h, houdini_href_e.c, houdini_html_e.c, houdini_html_u.c + +derive from https://github.com/vmg/houdini (with some modifications) + +Copyright (C) 2012 Vicent Martí + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +----- + +buffer.h, buffer.c, chunk.h + +are derived from code (C) 2012 Github, Inc. + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +----- + +utf8.c and utf8.c + +are derived from utf8proc +(), +(C) 2009 Public Software Group e. V., Berlin, Germany. + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. + +----- + +The normalization code in normalize.py was derived from the +markdowntest project, Copyright 2013 Karl Dubost: + +The MIT License (MIT) + +Copyright (c) 2013 Karl Dubost + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +----- + +The CommonMark spec (test/spec.txt) is + +Copyright (C) 2014-15 John MacFarlane + +Released under the Creative Commons CC-BY-SA 4.0 license: +. + +----- + +The test software in test/ is + +Copyright (c) 2014, John MacFarlane + +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +``` + +## fzf + +### License + +``` +The MIT License (MIT) + +Copyright (c) 2013-2024 Junegunn Choi +Copyright (c) 2021-2025 Simon Hauser + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +``` + # Microsoft Open Source This product also incorporates source code from other Microsoft open source projects, all licensed under the MIT license. diff --git a/NuGet.Config b/NuGet.Config index 272d5f0b40..57c3defd1d 100644 --- a/NuGet.Config +++ b/NuGet.Config @@ -4,7 +4,7 @@ - + diff --git a/OpenConsole.sln b/OpenConsole.sln index 5c5ec31054..fa94a4f8f0 100644 --- a/OpenConsole.sln +++ b/OpenConsole.sln @@ -131,7 +131,6 @@ EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "InteractivityWin32", "src\interactivity\win32\lib\win32.LIB.vcxproj", "{06EC74CB-9A12-429C-B551-8532EC964726}" ProjectSection(ProjectDependencies) = postProject {1C959542-BAC2-4E55-9A6D-13251914CBB9} = {1C959542-BAC2-4E55-9A6D-13251914CBB9} - {990F2657-8580-4828-943F-5DD657D11842} = {990F2657-8580-4828-943F-5DD657D11842} {AF0A096A-8B3A-4949-81EF-7DF8F0FEE91F} = {AF0A096A-8B3A-4949-81EF-7DF8F0FEE91F} EndProjectSection EndProject @@ -140,14 +139,9 @@ EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "InteractivityBase", "src\interactivity\base\lib\InteractivityBase.vcxproj", "{06EC74CB-9A12-429C-B551-8562EC964846}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Interactivity.Win32.Tests.Unit", "src\interactivity\win32\ut_interactivity_win32\Interactivity.Win32.UnitTests.vcxproj", "{D3B92829-26CB-411A-BDA2-7F5DA3D25DD4}" - ProjectSection(ProjectDependencies) = postProject - {990F2657-8580-4828-943F-5DD657D11842} = {990F2657-8580-4828-943F-5DD657D11842} - EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CloseTest", "src\tools\closetest\CloseTest.vcxproj", "{C7A6A5D9-60BE-4AEB-A5F6-AFE352F86CBB}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "RendererVt", "src\renderer\vt\lib\vt.vcxproj", "{990F2657-8580-4828-943F-5DD657D11842}" -EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "VtPipeTerm", "src\tools\vtpipeterm\VtPipeTerm.vcxproj", "{814DBDDE-894E-4327-A6E1-740504850098}" ProjectSection(ProjectDependencies) = postProject {9CBD7DFA-1754-4A9D-93D7-857A9D17CB1B} = {9CBD7DFA-1754-4A9D-93D7-857A9D17CB1B} @@ -157,8 +151,6 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ConEchoKey", "src\tools\ech EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Types", "src\types\lib\types.vcxproj", "{18D09A24-8240-42D6-8CB6-236EEE820263}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "RendererVt.unittest", "src\renderer\vt\ut_lib\vt.unittest.vcxproj", "{990F2657-8580-4828-943F-5DD657D11843}" -EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "BufferOut", "src\buffer\out\lib\bufferout.vcxproj", "{0CF235BD-2DA0-407E-90EE-C467E8BBC714}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TerminalConnection", "src\cascadia\TerminalConnection\TerminalConnection.vcxproj", "{CA5CAD1A-C46D-4588-B1C0-40F31AE9100B}" @@ -186,7 +178,6 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Microsoft.Terminal.Control" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "WindowsTerminal", "src\cascadia\WindowsTerminal\WindowsTerminal.vcxproj", "{CA5CAD1A-1754-4A9D-93D7-857A9D17CB1B}" ProjectSection(ProjectDependencies) = postProject - {27B5AAEB-A548-44CF-9777-F8BAA32AF7AE} = {27B5AAEB-A548-44CF-9777-F8BAA32AF7AE} {9CBD7DFA-1754-4A9D-93D7-857A9D17CB1B} = {9CBD7DFA-1754-4A9D-93D7-857A9D17CB1B} {CA5CAD1A-0B5E-45C3-96A8-BB496BFE4E32} = {CA5CAD1A-0B5E-45C3-96A8-BB496BFE4E32} {CA5CAD1A-44BD-4AC7-AC72-F16E576FDD12} = {CA5CAD1A-44BD-4AC7-AC72-F16E576FDD12} @@ -323,8 +314,6 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TerminalAzBridge", "src\cas {CA5CAD1A-C46D-4588-B1C0-40F31AE9100B} = {CA5CAD1A-C46D-4588-B1C0-40F31AE9100B} EndProjectSection EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "fmt", "src\dep\fmt\fmt.vcxproj", "{6BAE5851-50D5-4934-8D5E-30361A8A40F3}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WpfTerminalTestNetCore", "src\cascadia\WpfTerminalTestNetCore\WpfTerminalTestNetCore.csproj", "{1588FD7C-241E-4E7D-9113-43735F3E6BAD}" ProjectSection(ProjectDependencies) = postProject {CA5CAD1A-F542-4635-A069-7CAEFB930070} = {CA5CAD1A-F542-4635-A069-7CAEFB930070} @@ -358,19 +347,6 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "UnitTests_SettingsModel", " {CA5CAD1A-F542-4635-A069-7CAEFB930070} = {CA5CAD1A-F542-4635-A069-7CAEFB930070} EndProjectSection EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Microsoft.Terminal.Remoting.Lib", "src\cascadia\Remoting\Microsoft.Terminal.RemotingLib.vcxproj", "{43CE4CE5-0010-4B99-9569-672670D26E26}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Microsoft.Terminal.Remoting", "src\cascadia\Remoting\dll\Microsoft.Terminal.Remoting.vcxproj", "{27B5AAEB-A548-44CF-9777-F8BAA32AF7AE}" - ProjectSection(ProjectDependencies) = postProject - {43CE4CE5-0010-4B99-9569-672670D26E26} = {43CE4CE5-0010-4B99-9569-672670D26E26} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "UnitTests_Remoting", "src\cascadia\UnitTests_Remoting\Remoting.UnitTests.vcxproj", "{68A10CD3-AA64-465B-AF5F-ED4E9700543C}" - ProjectSection(ProjectDependencies) = postProject - {27B5AAEB-A548-44CF-9777-F8BAA32AF7AE} = {27B5AAEB-A548-44CF-9777-F8BAA32AF7AE} - {43CE4CE5-0010-4B99-9569-672670D26E26} = {43CE4CE5-0010-4B99-9569-672670D26E26} - EndProjectSection -EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "wpf", "wpf", "{4DAF0299-495E-4CD1-A982-9BAC16A45932}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "OpenConsoleProxy", "src\host\proxy\Host.Proxy.vcxproj", "{71CC9D78-BA29-4D93-946F-BEF5D9A3A6EF}" @@ -408,6 +384,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "RenderingTests", "src\tools EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Microsoft.Terminal.UI", "src\cascadia\UIHelpers\UIHelpers.vcxproj", "{6515F03F-E56D-4DB4-B23D-AC4FB80DB36F}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Microsoft.Terminal.UI.Markdown", "src\cascadia\UIMarkdown\UIMarkdown.vcxproj", "{7615F03F-E56D-4DB4-B23D-BD4FB80DB36F}" +EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "benchcat", "src\tools\benchcat\benchcat.vcxproj", "{2C836962-9543-4CE5-B834-D28E1F124B66}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ConsoleMonitor", "src\tools\ConsoleMonitor\ConsoleMonitor.vcxproj", "{328729E9-6723-416E-9C98-951F1473BBE1}" @@ -1112,29 +1090,6 @@ Global {C7A6A5D9-60BE-4AEB-A5F6-AFE352F86CBB}.Release|x64.Build.0 = Release|x64 {C7A6A5D9-60BE-4AEB-A5F6-AFE352F86CBB}.Release|x86.ActiveCfg = Release|Win32 {C7A6A5D9-60BE-4AEB-A5F6-AFE352F86CBB}.Release|x86.Build.0 = Release|Win32 - {990F2657-8580-4828-943F-5DD657D11842}.AuditMode|Any CPU.ActiveCfg = AuditMode|Win32 - {990F2657-8580-4828-943F-5DD657D11842}.AuditMode|ARM64.ActiveCfg = Release|ARM64 - {990F2657-8580-4828-943F-5DD657D11842}.AuditMode|x64.ActiveCfg = Release|x64 - {990F2657-8580-4828-943F-5DD657D11842}.AuditMode|x86.ActiveCfg = Release|Win32 - {990F2657-8580-4828-943F-5DD657D11842}.Debug|Any CPU.ActiveCfg = Debug|Win32 - {990F2657-8580-4828-943F-5DD657D11842}.Debug|ARM64.ActiveCfg = Debug|ARM64 - {990F2657-8580-4828-943F-5DD657D11842}.Debug|ARM64.Build.0 = Debug|ARM64 - {990F2657-8580-4828-943F-5DD657D11842}.Debug|x64.ActiveCfg = Debug|x64 - {990F2657-8580-4828-943F-5DD657D11842}.Debug|x64.Build.0 = Debug|x64 - {990F2657-8580-4828-943F-5DD657D11842}.Debug|x86.ActiveCfg = Debug|Win32 - {990F2657-8580-4828-943F-5DD657D11842}.Debug|x86.Build.0 = Debug|Win32 - {990F2657-8580-4828-943F-5DD657D11842}.Fuzzing|Any CPU.ActiveCfg = Fuzzing|Win32 - {990F2657-8580-4828-943F-5DD657D11842}.Fuzzing|ARM64.ActiveCfg = Fuzzing|ARM64 - {990F2657-8580-4828-943F-5DD657D11842}.Fuzzing|x64.ActiveCfg = Fuzzing|x64 - {990F2657-8580-4828-943F-5DD657D11842}.Fuzzing|x64.Build.0 = Fuzzing|x64 - {990F2657-8580-4828-943F-5DD657D11842}.Fuzzing|x86.ActiveCfg = Fuzzing|Win32 - {990F2657-8580-4828-943F-5DD657D11842}.Release|Any CPU.ActiveCfg = Release|Win32 - {990F2657-8580-4828-943F-5DD657D11842}.Release|ARM64.ActiveCfg = Release|ARM64 - {990F2657-8580-4828-943F-5DD657D11842}.Release|ARM64.Build.0 = Release|ARM64 - {990F2657-8580-4828-943F-5DD657D11842}.Release|x64.ActiveCfg = Release|x64 - {990F2657-8580-4828-943F-5DD657D11842}.Release|x64.Build.0 = Release|x64 - {990F2657-8580-4828-943F-5DD657D11842}.Release|x86.ActiveCfg = Release|Win32 - {990F2657-8580-4828-943F-5DD657D11842}.Release|x86.Build.0 = Release|Win32 {814DBDDE-894E-4327-A6E1-740504850098}.AuditMode|Any CPU.ActiveCfg = AuditMode|Win32 {814DBDDE-894E-4327-A6E1-740504850098}.AuditMode|ARM64.ActiveCfg = Release|ARM64 {814DBDDE-894E-4327-A6E1-740504850098}.AuditMode|x64.ActiveCfg = Release|x64 @@ -1205,28 +1160,6 @@ Global {18D09A24-8240-42D6-8CB6-236EEE820263}.Release|x64.Build.0 = Release|x64 {18D09A24-8240-42D6-8CB6-236EEE820263}.Release|x86.ActiveCfg = Release|Win32 {18D09A24-8240-42D6-8CB6-236EEE820263}.Release|x86.Build.0 = Release|Win32 - {990F2657-8580-4828-943F-5DD657D11843}.AuditMode|Any CPU.ActiveCfg = AuditMode|Win32 - {990F2657-8580-4828-943F-5DD657D11843}.AuditMode|ARM64.ActiveCfg = Release|ARM64 - {990F2657-8580-4828-943F-5DD657D11843}.AuditMode|x64.ActiveCfg = Release|x64 - {990F2657-8580-4828-943F-5DD657D11843}.AuditMode|x86.ActiveCfg = Release|Win32 - {990F2657-8580-4828-943F-5DD657D11843}.Debug|Any CPU.ActiveCfg = Debug|Win32 - {990F2657-8580-4828-943F-5DD657D11843}.Debug|ARM64.ActiveCfg = Debug|ARM64 - {990F2657-8580-4828-943F-5DD657D11843}.Debug|ARM64.Build.0 = Debug|ARM64 - {990F2657-8580-4828-943F-5DD657D11843}.Debug|x64.ActiveCfg = Debug|x64 - {990F2657-8580-4828-943F-5DD657D11843}.Debug|x64.Build.0 = Debug|x64 - {990F2657-8580-4828-943F-5DD657D11843}.Debug|x86.ActiveCfg = Debug|Win32 - {990F2657-8580-4828-943F-5DD657D11843}.Debug|x86.Build.0 = Debug|Win32 - {990F2657-8580-4828-943F-5DD657D11843}.Fuzzing|Any CPU.ActiveCfg = Fuzzing|Win32 - {990F2657-8580-4828-943F-5DD657D11843}.Fuzzing|ARM64.ActiveCfg = Fuzzing|ARM64 - {990F2657-8580-4828-943F-5DD657D11843}.Fuzzing|x64.ActiveCfg = Fuzzing|x64 - {990F2657-8580-4828-943F-5DD657D11843}.Fuzzing|x86.ActiveCfg = Fuzzing|Win32 - {990F2657-8580-4828-943F-5DD657D11843}.Release|Any CPU.ActiveCfg = Release|Win32 - {990F2657-8580-4828-943F-5DD657D11843}.Release|ARM64.ActiveCfg = Release|ARM64 - {990F2657-8580-4828-943F-5DD657D11843}.Release|ARM64.Build.0 = Release|ARM64 - {990F2657-8580-4828-943F-5DD657D11843}.Release|x64.ActiveCfg = Release|x64 - {990F2657-8580-4828-943F-5DD657D11843}.Release|x64.Build.0 = Release|x64 - {990F2657-8580-4828-943F-5DD657D11843}.Release|x86.ActiveCfg = Release|Win32 - {990F2657-8580-4828-943F-5DD657D11843}.Release|x86.Build.0 = Release|Win32 {0CF235BD-2DA0-407E-90EE-C467E8BBC714}.AuditMode|Any CPU.ActiveCfg = AuditMode|Win32 {0CF235BD-2DA0-407E-90EE-C467E8BBC714}.AuditMode|ARM64.ActiveCfg = AuditMode|ARM64 {0CF235BD-2DA0-407E-90EE-C467E8BBC714}.AuditMode|ARM64.Build.0 = AuditMode|ARM64 @@ -1794,32 +1727,6 @@ Global {067F0A06-FCB7-472C-96E9-B03B54E8E18D}.Release|x64.Build.0 = Release|x64 {067F0A06-FCB7-472C-96E9-B03B54E8E18D}.Release|x86.ActiveCfg = Release|Win32 {067F0A06-FCB7-472C-96E9-B03B54E8E18D}.Release|x86.Build.0 = Release|Win32 - {6BAE5851-50D5-4934-8D5E-30361A8A40F3}.AuditMode|Any CPU.ActiveCfg = AuditMode|Win32 - {6BAE5851-50D5-4934-8D5E-30361A8A40F3}.AuditMode|ARM64.ActiveCfg = AuditMode|ARM64 - {6BAE5851-50D5-4934-8D5E-30361A8A40F3}.AuditMode|ARM64.Build.0 = AuditMode|ARM64 - {6BAE5851-50D5-4934-8D5E-30361A8A40F3}.AuditMode|x64.ActiveCfg = AuditMode|x64 - {6BAE5851-50D5-4934-8D5E-30361A8A40F3}.AuditMode|x64.Build.0 = AuditMode|x64 - {6BAE5851-50D5-4934-8D5E-30361A8A40F3}.AuditMode|x86.ActiveCfg = AuditMode|Win32 - {6BAE5851-50D5-4934-8D5E-30361A8A40F3}.AuditMode|x86.Build.0 = AuditMode|Win32 - {6BAE5851-50D5-4934-8D5E-30361A8A40F3}.Debug|Any CPU.ActiveCfg = Debug|Win32 - {6BAE5851-50D5-4934-8D5E-30361A8A40F3}.Debug|ARM64.ActiveCfg = Debug|ARM64 - {6BAE5851-50D5-4934-8D5E-30361A8A40F3}.Debug|ARM64.Build.0 = Debug|ARM64 - {6BAE5851-50D5-4934-8D5E-30361A8A40F3}.Debug|x64.ActiveCfg = Debug|x64 - {6BAE5851-50D5-4934-8D5E-30361A8A40F3}.Debug|x64.Build.0 = Debug|x64 - {6BAE5851-50D5-4934-8D5E-30361A8A40F3}.Debug|x86.ActiveCfg = Debug|Win32 - {6BAE5851-50D5-4934-8D5E-30361A8A40F3}.Debug|x86.Build.0 = Debug|Win32 - {6BAE5851-50D5-4934-8D5E-30361A8A40F3}.Fuzzing|Any CPU.ActiveCfg = Fuzzing|Win32 - {6BAE5851-50D5-4934-8D5E-30361A8A40F3}.Fuzzing|ARM64.ActiveCfg = Fuzzing|ARM64 - {6BAE5851-50D5-4934-8D5E-30361A8A40F3}.Fuzzing|x64.ActiveCfg = Fuzzing|x64 - {6BAE5851-50D5-4934-8D5E-30361A8A40F3}.Fuzzing|x64.Build.0 = Fuzzing|x64 - {6BAE5851-50D5-4934-8D5E-30361A8A40F3}.Fuzzing|x86.ActiveCfg = Fuzzing|Win32 - {6BAE5851-50D5-4934-8D5E-30361A8A40F3}.Release|Any CPU.ActiveCfg = Release|Win32 - {6BAE5851-50D5-4934-8D5E-30361A8A40F3}.Release|ARM64.ActiveCfg = Release|ARM64 - {6BAE5851-50D5-4934-8D5E-30361A8A40F3}.Release|ARM64.Build.0 = Release|ARM64 - {6BAE5851-50D5-4934-8D5E-30361A8A40F3}.Release|x64.ActiveCfg = Release|x64 - {6BAE5851-50D5-4934-8D5E-30361A8A40F3}.Release|x64.Build.0 = Release|x64 - {6BAE5851-50D5-4934-8D5E-30361A8A40F3}.Release|x86.ActiveCfg = Release|Win32 - {6BAE5851-50D5-4934-8D5E-30361A8A40F3}.Release|x86.Build.0 = Release|Win32 {1588FD7C-241E-4E7D-9113-43735F3E6BAD}.AuditMode|Any CPU.ActiveCfg = Debug|Any CPU {1588FD7C-241E-4E7D-9113-43735F3E6BAD}.AuditMode|ARM64.ActiveCfg = Debug|Any CPU {1588FD7C-241E-4E7D-9113-43735F3E6BAD}.AuditMode|x64.ActiveCfg = Debug|Any CPU @@ -1997,79 +1904,6 @@ Global {CA5CAD1A-9B68-456A-B13E-C8218070DC42}.Release|x64.Build.0 = Release|x64 {CA5CAD1A-9B68-456A-B13E-C8218070DC42}.Release|x86.ActiveCfg = Release|Win32 {CA5CAD1A-9B68-456A-B13E-C8218070DC42}.Release|x86.Build.0 = Release|Win32 - {43CE4CE5-0010-4B99-9569-672670D26E26}.AuditMode|Any CPU.ActiveCfg = AuditMode|Win32 - {43CE4CE5-0010-4B99-9569-672670D26E26}.AuditMode|ARM64.ActiveCfg = AuditMode|ARM64 - {43CE4CE5-0010-4B99-9569-672670D26E26}.AuditMode|ARM64.Build.0 = AuditMode|ARM64 - {43CE4CE5-0010-4B99-9569-672670D26E26}.AuditMode|x64.ActiveCfg = Release|x64 - {43CE4CE5-0010-4B99-9569-672670D26E26}.AuditMode|x64.Build.0 = Release|x64 - {43CE4CE5-0010-4B99-9569-672670D26E26}.AuditMode|x86.ActiveCfg = AuditMode|Win32 - {43CE4CE5-0010-4B99-9569-672670D26E26}.AuditMode|x86.Build.0 = AuditMode|Win32 - {43CE4CE5-0010-4B99-9569-672670D26E26}.Debug|Any CPU.ActiveCfg = Debug|Win32 - {43CE4CE5-0010-4B99-9569-672670D26E26}.Debug|ARM64.ActiveCfg = Debug|ARM64 - {43CE4CE5-0010-4B99-9569-672670D26E26}.Debug|ARM64.Build.0 = Debug|ARM64 - {43CE4CE5-0010-4B99-9569-672670D26E26}.Debug|x64.ActiveCfg = Debug|x64 - {43CE4CE5-0010-4B99-9569-672670D26E26}.Debug|x64.Build.0 = Debug|x64 - {43CE4CE5-0010-4B99-9569-672670D26E26}.Debug|x86.ActiveCfg = Debug|Win32 - {43CE4CE5-0010-4B99-9569-672670D26E26}.Debug|x86.Build.0 = Debug|Win32 - {43CE4CE5-0010-4B99-9569-672670D26E26}.Fuzzing|Any CPU.ActiveCfg = Fuzzing|Win32 - {43CE4CE5-0010-4B99-9569-672670D26E26}.Fuzzing|ARM64.ActiveCfg = Fuzzing|ARM64 - {43CE4CE5-0010-4B99-9569-672670D26E26}.Fuzzing|x64.ActiveCfg = Fuzzing|x64 - {43CE4CE5-0010-4B99-9569-672670D26E26}.Fuzzing|x86.ActiveCfg = Fuzzing|Win32 - {43CE4CE5-0010-4B99-9569-672670D26E26}.Release|Any CPU.ActiveCfg = Release|Win32 - {43CE4CE5-0010-4B99-9569-672670D26E26}.Release|ARM64.ActiveCfg = Release|ARM64 - {43CE4CE5-0010-4B99-9569-672670D26E26}.Release|ARM64.Build.0 = Release|ARM64 - {43CE4CE5-0010-4B99-9569-672670D26E26}.Release|x64.ActiveCfg = Release|x64 - {43CE4CE5-0010-4B99-9569-672670D26E26}.Release|x64.Build.0 = Release|x64 - {43CE4CE5-0010-4B99-9569-672670D26E26}.Release|x86.ActiveCfg = Release|Win32 - {43CE4CE5-0010-4B99-9569-672670D26E26}.Release|x86.Build.0 = Release|Win32 - {27B5AAEB-A548-44CF-9777-F8BAA32AF7AE}.AuditMode|Any CPU.ActiveCfg = AuditMode|Win32 - {27B5AAEB-A548-44CF-9777-F8BAA32AF7AE}.AuditMode|ARM64.ActiveCfg = AuditMode|ARM64 - {27B5AAEB-A548-44CF-9777-F8BAA32AF7AE}.AuditMode|ARM64.Build.0 = AuditMode|ARM64 - {27B5AAEB-A548-44CF-9777-F8BAA32AF7AE}.AuditMode|x64.ActiveCfg = Release|x64 - {27B5AAEB-A548-44CF-9777-F8BAA32AF7AE}.AuditMode|x86.ActiveCfg = AuditMode|Win32 - {27B5AAEB-A548-44CF-9777-F8BAA32AF7AE}.AuditMode|x86.Build.0 = AuditMode|Win32 - {27B5AAEB-A548-44CF-9777-F8BAA32AF7AE}.Debug|Any CPU.ActiveCfg = Debug|Win32 - {27B5AAEB-A548-44CF-9777-F8BAA32AF7AE}.Debug|ARM64.ActiveCfg = Debug|ARM64 - {27B5AAEB-A548-44CF-9777-F8BAA32AF7AE}.Debug|ARM64.Build.0 = Debug|ARM64 - {27B5AAEB-A548-44CF-9777-F8BAA32AF7AE}.Debug|x64.ActiveCfg = Debug|x64 - {27B5AAEB-A548-44CF-9777-F8BAA32AF7AE}.Debug|x64.Build.0 = Debug|x64 - {27B5AAEB-A548-44CF-9777-F8BAA32AF7AE}.Debug|x86.ActiveCfg = Debug|Win32 - {27B5AAEB-A548-44CF-9777-F8BAA32AF7AE}.Debug|x86.Build.0 = Debug|Win32 - {27B5AAEB-A548-44CF-9777-F8BAA32AF7AE}.Fuzzing|Any CPU.ActiveCfg = Fuzzing|Win32 - {27B5AAEB-A548-44CF-9777-F8BAA32AF7AE}.Fuzzing|ARM64.ActiveCfg = Fuzzing|ARM64 - {27B5AAEB-A548-44CF-9777-F8BAA32AF7AE}.Fuzzing|x64.ActiveCfg = Fuzzing|x64 - {27B5AAEB-A548-44CF-9777-F8BAA32AF7AE}.Fuzzing|x86.ActiveCfg = Fuzzing|Win32 - {27B5AAEB-A548-44CF-9777-F8BAA32AF7AE}.Release|Any CPU.ActiveCfg = Release|Win32 - {27B5AAEB-A548-44CF-9777-F8BAA32AF7AE}.Release|ARM64.ActiveCfg = Release|ARM64 - {27B5AAEB-A548-44CF-9777-F8BAA32AF7AE}.Release|ARM64.Build.0 = Release|ARM64 - {27B5AAEB-A548-44CF-9777-F8BAA32AF7AE}.Release|x64.ActiveCfg = Release|x64 - {27B5AAEB-A548-44CF-9777-F8BAA32AF7AE}.Release|x64.Build.0 = Release|x64 - {27B5AAEB-A548-44CF-9777-F8BAA32AF7AE}.Release|x86.ActiveCfg = Release|Win32 - {27B5AAEB-A548-44CF-9777-F8BAA32AF7AE}.Release|x86.Build.0 = Release|Win32 - {68A10CD3-AA64-465B-AF5F-ED4E9700543C}.AuditMode|Any CPU.ActiveCfg = AuditMode|Win32 - {68A10CD3-AA64-465B-AF5F-ED4E9700543C}.AuditMode|ARM64.ActiveCfg = AuditMode|ARM64 - {68A10CD3-AA64-465B-AF5F-ED4E9700543C}.AuditMode|ARM64.Build.0 = AuditMode|ARM64 - {68A10CD3-AA64-465B-AF5F-ED4E9700543C}.AuditMode|x64.ActiveCfg = AuditMode|x64 - {68A10CD3-AA64-465B-AF5F-ED4E9700543C}.AuditMode|x86.ActiveCfg = AuditMode|Win32 - {68A10CD3-AA64-465B-AF5F-ED4E9700543C}.AuditMode|x86.Build.0 = AuditMode|Win32 - {68A10CD3-AA64-465B-AF5F-ED4E9700543C}.Debug|Any CPU.ActiveCfg = Debug|Win32 - {68A10CD3-AA64-465B-AF5F-ED4E9700543C}.Debug|ARM64.ActiveCfg = Debug|ARM64 - {68A10CD3-AA64-465B-AF5F-ED4E9700543C}.Debug|ARM64.Build.0 = Debug|ARM64 - {68A10CD3-AA64-465B-AF5F-ED4E9700543C}.Debug|x64.ActiveCfg = Debug|x64 - {68A10CD3-AA64-465B-AF5F-ED4E9700543C}.Debug|x64.Build.0 = Debug|x64 - {68A10CD3-AA64-465B-AF5F-ED4E9700543C}.Debug|x86.ActiveCfg = Debug|Win32 - {68A10CD3-AA64-465B-AF5F-ED4E9700543C}.Debug|x86.Build.0 = Debug|Win32 - {68A10CD3-AA64-465B-AF5F-ED4E9700543C}.Fuzzing|Any CPU.ActiveCfg = Fuzzing|Win32 - {68A10CD3-AA64-465B-AF5F-ED4E9700543C}.Fuzzing|ARM64.ActiveCfg = Fuzzing|ARM64 - {68A10CD3-AA64-465B-AF5F-ED4E9700543C}.Fuzzing|x64.ActiveCfg = Fuzzing|x64 - {68A10CD3-AA64-465B-AF5F-ED4E9700543C}.Fuzzing|x86.ActiveCfg = Fuzzing|Win32 - {68A10CD3-AA64-465B-AF5F-ED4E9700543C}.Release|Any CPU.ActiveCfg = Release|Win32 - {68A10CD3-AA64-465B-AF5F-ED4E9700543C}.Release|ARM64.ActiveCfg = Release|ARM64 - {68A10CD3-AA64-465B-AF5F-ED4E9700543C}.Release|ARM64.Build.0 = Release|ARM64 - {68A10CD3-AA64-465B-AF5F-ED4E9700543C}.Release|x64.ActiveCfg = Release|x64 - {68A10CD3-AA64-465B-AF5F-ED4E9700543C}.Release|x64.Build.0 = Release|x64 - {68A10CD3-AA64-465B-AF5F-ED4E9700543C}.Release|x86.ActiveCfg = Release|Win32 - {68A10CD3-AA64-465B-AF5F-ED4E9700543C}.Release|x86.Build.0 = Release|Win32 {71CC9D78-BA29-4D93-946F-BEF5D9A3A6EF}.AuditMode|Any CPU.ActiveCfg = AuditMode|Win32 {71CC9D78-BA29-4D93-946F-BEF5D9A3A6EF}.AuditMode|ARM64.ActiveCfg = AuditMode|ARM64 {71CC9D78-BA29-4D93-946F-BEF5D9A3A6EF}.AuditMode|ARM64.Build.0 = AuditMode|ARM64 @@ -2320,6 +2154,32 @@ Global {6515F03F-E56D-4DB4-B23D-AC4FB80DB36F}.Release|x64.Build.0 = Release|x64 {6515F03F-E56D-4DB4-B23D-AC4FB80DB36F}.Release|x86.ActiveCfg = Release|Win32 {6515F03F-E56D-4DB4-B23D-AC4FB80DB36F}.Release|x86.Build.0 = Release|Win32 + {7615F03F-E56D-4DB4-B23D-BD4FB80DB36F}.AuditMode|Any CPU.ActiveCfg = AuditMode|x64 + {7615F03F-E56D-4DB4-B23D-BD4FB80DB36F}.AuditMode|Any CPU.Build.0 = AuditMode|x64 + {7615F03F-E56D-4DB4-B23D-BD4FB80DB36F}.AuditMode|ARM64.ActiveCfg = AuditMode|ARM64 + {7615F03F-E56D-4DB4-B23D-BD4FB80DB36F}.AuditMode|ARM64.Build.0 = AuditMode|ARM64 + {7615F03F-E56D-4DB4-B23D-BD4FB80DB36F}.AuditMode|x64.ActiveCfg = AuditMode|x64 + {7615F03F-E56D-4DB4-B23D-BD4FB80DB36F}.AuditMode|x64.Build.0 = AuditMode|x64 + {7615F03F-E56D-4DB4-B23D-BD4FB80DB36F}.AuditMode|x86.ActiveCfg = AuditMode|Win32 + {7615F03F-E56D-4DB4-B23D-BD4FB80DB36F}.AuditMode|x86.Build.0 = AuditMode|Win32 + {7615F03F-E56D-4DB4-B23D-BD4FB80DB36F}.Debug|Any CPU.ActiveCfg = Debug|x64 + {7615F03F-E56D-4DB4-B23D-BD4FB80DB36F}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {7615F03F-E56D-4DB4-B23D-BD4FB80DB36F}.Debug|ARM64.Build.0 = Debug|ARM64 + {7615F03F-E56D-4DB4-B23D-BD4FB80DB36F}.Debug|x64.ActiveCfg = Debug|x64 + {7615F03F-E56D-4DB4-B23D-BD4FB80DB36F}.Debug|x64.Build.0 = Debug|x64 + {7615F03F-E56D-4DB4-B23D-BD4FB80DB36F}.Debug|x86.ActiveCfg = Debug|Win32 + {7615F03F-E56D-4DB4-B23D-BD4FB80DB36F}.Debug|x86.Build.0 = Debug|Win32 + {7615F03F-E56D-4DB4-B23D-BD4FB80DB36F}.Fuzzing|Any CPU.ActiveCfg = Fuzzing|x64 + {7615F03F-E56D-4DB4-B23D-BD4FB80DB36F}.Fuzzing|ARM64.ActiveCfg = Fuzzing|ARM64 + {7615F03F-E56D-4DB4-B23D-BD4FB80DB36F}.Fuzzing|x64.ActiveCfg = Fuzzing|x64 + {7615F03F-E56D-4DB4-B23D-BD4FB80DB36F}.Fuzzing|x86.ActiveCfg = Fuzzing|Win32 + {7615F03F-E56D-4DB4-B23D-BD4FB80DB36F}.Release|Any CPU.ActiveCfg = Release|x64 + {7615F03F-E56D-4DB4-B23D-BD4FB80DB36F}.Release|ARM64.ActiveCfg = Release|ARM64 + {7615F03F-E56D-4DB4-B23D-BD4FB80DB36F}.Release|ARM64.Build.0 = Release|ARM64 + {7615F03F-E56D-4DB4-B23D-BD4FB80DB36F}.Release|x64.ActiveCfg = Release|x64 + {7615F03F-E56D-4DB4-B23D-BD4FB80DB36F}.Release|x64.Build.0 = Release|x64 + {7615F03F-E56D-4DB4-B23D-BD4FB80DB36F}.Release|x86.ActiveCfg = Release|Win32 + {7615F03F-E56D-4DB4-B23D-BD4FB80DB36F}.Release|x86.Build.0 = Release|Win32 {2C836962-9543-4CE5-B834-D28E1F124B66}.AuditMode|Any CPU.ActiveCfg = AuditMode|Win32 {2C836962-9543-4CE5-B834-D28E1F124B66}.AuditMode|ARM64.ActiveCfg = Release|ARM64 {2C836962-9543-4CE5-B834-D28E1F124B66}.AuditMode|x64.ActiveCfg = Release|x64 @@ -2409,11 +2269,9 @@ Global {06EC74CB-9A12-429C-B551-8562EC964846} = {E8F24881-5E37-4362-B191-A3BA0ED7F4EB} {D3B92829-26CB-411A-BDA2-7F5DA3D25DD4} = {E8F24881-5E37-4362-B191-A3BA0ED7F4EB} {C7A6A5D9-60BE-4AEB-A5F6-AFE352F86CBB} = {A10C4720-DCA4-4640-9749-67F4314F527C} - {990F2657-8580-4828-943F-5DD657D11842} = {05500DEF-2294-41E3-AF9A-24E580B82836} {814DBDDE-894E-4327-A6E1-740504850098} = {A10C4720-DCA4-4640-9749-67F4314F527C} {814CBEEE-894E-4327-A6E1-740504850098} = {A10C4720-DCA4-4640-9749-67F4314F527C} {18D09A24-8240-42D6-8CB6-236EEE820263} = {89CDCC5C-9F53-4054-97A4-639D99F169CD} - {990F2657-8580-4828-943F-5DD657D11843} = {05500DEF-2294-41E3-AF9A-24E580B82836} {0CF235BD-2DA0-407E-90EE-C467E8BBC714} = {1E4A062E-293B-4817-B20D-BF16B979E350} {CA5CAD1A-C46D-4588-B1C0-40F31AE9100B} = {59840756-302F-44DF-AA47-441A9D673202} {CA5CAD1A-ABCD-429C-B551-8562EC954746} = {9921CA0A-320C-4460-8623-3A3196E7F4CB} @@ -2446,7 +2304,6 @@ Global {D3EF7B96-CD5E-47C9-B9A9-136259563033} = {04170EEF-983A-4195-BFEF-2321E5E38A1E} {024052DE-83FB-4653-AEA4-90790D29D5BD} = {E8F24881-5E37-4362-B191-A3BA0ED7F4EB} {067F0A06-FCB7-472C-96E9-B03B54E8E18D} = {61901E80-E97D-4D61-A9BB-E8F2FDA8B40C} - {6BAE5851-50D5-4934-8D5E-30361A8A40F3} = {81C352DB-1818-45B7-A284-18E259F1CC87} {1588FD7C-241E-4E7D-9113-43735F3E6BAD} = {4DAF0299-495E-4CD1-A982-9BAC16A45932} {506FD703-BAA7-4F6E-9361-64F550EC8FCA} = {61901E80-E97D-4D61-A9BB-E8F2FDA8B40C} {416FD703-BAA7-4F6E-9361-64F550EC8FCA} = {61901E80-E97D-4D61-A9BB-E8F2FDA8B40C} @@ -2454,9 +2311,6 @@ Global {CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907} = {77875138-BB08-49F9-8BB1-409C2150E0E1} {CA5CAD1A-082C-4476-9F33-94B339494076} = {77875138-BB08-49F9-8BB1-409C2150E0E1} {CA5CAD1A-9B68-456A-B13E-C8218070DC42} = {BDB237B6-1D1D-400F-84CC-40A58FA59C8E} - {43CE4CE5-0010-4B99-9569-672670D26E26} = {2D17E75D-2DDC-42C4-AD70-704D95A937AE} - {27B5AAEB-A548-44CF-9777-F8BAA32AF7AE} = {2D17E75D-2DDC-42C4-AD70-704D95A937AE} - {68A10CD3-AA64-465B-AF5F-ED4E9700543C} = {BDB237B6-1D1D-400F-84CC-40A58FA59C8E} {4DAF0299-495E-4CD1-A982-9BAC16A45932} = {59840756-302F-44DF-AA47-441A9D673202} {71CC9D78-BA29-4D93-946F-BEF5D9A3A6EF} = {E8F24881-5E37-4362-B191-A3BA0ED7F4EB} {2D17E75D-2DDC-42C4-AD70-704D95A937AE} = {59840756-302F-44DF-AA47-441A9D673202} @@ -2474,6 +2328,7 @@ Global {613CCB57-5FA9-48EF-80D0-6B1E319E20C4} = {A10C4720-DCA4-4640-9749-67F4314F527C} {37C995E0-2349-4154-8E77-4A52C0C7F46D} = {A10C4720-DCA4-4640-9749-67F4314F527C} {6515F03F-E56D-4DB4-B23D-AC4FB80DB36F} = {61901E80-E97D-4D61-A9BB-E8F2FDA8B40C} + {7615F03F-E56D-4DB4-B23D-BD4FB80DB36F} = {61901E80-E97D-4D61-A9BB-E8F2FDA8B40C} {2C836962-9543-4CE5-B834-D28E1F124B66} = {A10C4720-DCA4-4640-9749-67F4314F527C} {328729E9-6723-416E-9C98-951F1473BBE1} = {A10C4720-DCA4-4640-9749-67F4314F527C} {BE92101C-04F8-48DA-99F0-E1F4F1D2DC48} = {A10C4720-DCA4-4640-9749-67F4314F527C} diff --git a/README.md b/README.md index 462731aa59..e178ad2eb3 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,45 @@ ![terminal-logos](https://github.com/microsoft/terminal/assets/91625426/333ddc76-8ab2-4eb4-a8c0-4d7b953b1179) +[![Terminal Build Status](https://dev.azure.com/shine-oss/terminal/_apis/build/status%2FTerminal%20CI?branchName=main)](https://dev.azure.com/shine-oss/terminal/_build/latest?definitionId=1&branchName=main) + # Welcome to the Windows Terminal, Console and Command-Line repo +
+ Table of Contents + +- [Installing and running Windows Terminal](#installing-and-running-windows-terminal) + - [Microsoft Store \[Recommended\]](#microsoft-store-recommended) + - [Other install methods](#other-install-methods) + - [Via GitHub](#via-github) + - [Via Windows Package Manager CLI (aka winget)](#via-windows-package-manager-cli-aka-winget) + - [Via Chocolatey (unofficial)](#via-chocolatey-unofficial) + - [Via Scoop (unofficial)](#via-scoop-unofficial) +- [Installing Windows Terminal Canary](#installing-windows-terminal-canary) +- [Windows Terminal Roadmap](#windows-terminal-roadmap) +- [Terminal \& Console Overview](#terminal--console-overview) + - [Windows Terminal](#windows-terminal) + - [The Windows Console Host](#the-windows-console-host) + - [Shared Components](#shared-components) + - [Creating the new Windows Terminal](#creating-the-new-windows-terminal) +- [Resources](#resources) +- [FAQ](#faq) + - [I built and ran the new Terminal, but it looks just like the old console](#i-built-and-ran-the-new-terminal-but-it-looks-just-like-the-old-console) +- [Documentation](#documentation) +- [Contributing](#contributing) +- [Communicating with the Team](#communicating-with-the-team) +- [Developer Guidance](#developer-guidance) +- [Prerequisites](#prerequisites) +- [Building the Code](#building-the-code) + - [Building in PowerShell](#building-in-powershell) + - [Building in Cmd](#building-in-cmd) +- [Running \& Debugging](#running--debugging) + - [Coding Guidance](#coding-guidance) +- [Code of Conduct](#code-of-conduct) + +
+ +
+ This repository contains the source code for: * [Windows Terminal](https://aka.ms/terminal) @@ -145,15 +183,6 @@ _Learn more about the [types of Windows Terminal distributions](https://learn.mi The plan for the Windows Terminal [is described here](/doc/roadmap-2023.md) and will be updated as the project proceeds. -## Project Build Status - -Project|Build Status ----|--- -Terminal|[![Terminal Build Status](https://dev.azure.com/ms/terminal/_apis/build/status/terminal%20CI?branchName=main)](https://dev.azure.com/ms/terminal/_build?definitionId=136) -ColorTool|![Colortool Build Status](https://microsoft.visualstudio.com/_apis/public/build/definitions/c93e867a-8815-43c1-92c4-e7dd5404f1e1/17023/badge) - ---- - ## Terminal & Console Overview Please take a few minutes to review the overview below before diving into the @@ -311,6 +340,19 @@ If you would like to ask a question that you feel doesn't warrant an issue ## Prerequisites +You can configure your environment to build Terminal in one of two ways: + +### Using WinGet configuration file + +After cloning the repository, you can use a [WinGet configuration file](https://learn.microsoft.com/en-us/windows/package-manager/configuration/#use-a-winget-configuration-file-to-configure-your-machine) +to set up your environment. The [default configuration file](.config/configuration.winget) installs Visual Studio 2022 Community & rest of the required tools. There are two other variants of the configuration file available in the [.config](.config) directory for Enterprise & Professional editions of Visual Studio 2022. To run the default configuration file, you can either double-click the file from explorer or run the following command: + +```powershell +winget configure .config\configuration.winget +``` + +### Manual configuration + * You must be running Windows 10 2004 (build >= 10.0.19041.0) or later to run Windows Terminal * You must [enable Developer Mode in the Windows Settings @@ -333,15 +375,6 @@ If you would like to ask a question that you feel doesn't warrant an issue ## Building the Code -This repository uses [git -submodules](https://git-scm.com/book/en/v2/Git-Tools-Submodules) for some of its -dependencies. To make sure submodules are restored or updated, be sure to run -the following prior to building: - -```shell -git submodule update --init --recursive -``` - OpenConsole.sln may be built from within Visual Studio or from the command-line using a set of convenience scripts & tools in the **/tools** directory: diff --git a/Scratch.sln b/Scratch.sln index d14a85a64f..0015f5d832 100644 --- a/Scratch.sln +++ b/Scratch.sln @@ -29,8 +29,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Common Props", "Common Prop src\wap-common.build.pre.props = src\wap-common.build.pre.props EndProjectSection EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "fmt", "src\dep\fmt\fmt.vcxproj", "{6BAE5851-50D5-4934-8D5E-30361A8A40F3}" -EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Types", "src\types\lib\types.vcxproj", "{18D09A24-8240-42D6-8CB6-236EEE820263}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "dependencies", "dependencies", "{75AC9360-76FD-4ABC-AFEC-EF342BD2B3E9}" @@ -159,30 +157,6 @@ Global {B4427499-9FDE-4208-B456-5BC580637633}.Release|x64.Build.0 = Release|x64 {B4427499-9FDE-4208-B456-5BC580637633}.Release|x86.ActiveCfg = Release|Win32 {B4427499-9FDE-4208-B456-5BC580637633}.Release|x86.Build.0 = Release|Win32 - {6BAE5851-50D5-4934-8D5E-30361A8A40F3}.AuditMode|ARM64.ActiveCfg = AuditMode|ARM64 - {6BAE5851-50D5-4934-8D5E-30361A8A40F3}.AuditMode|ARM64.Build.0 = AuditMode|ARM64 - {6BAE5851-50D5-4934-8D5E-30361A8A40F3}.AuditMode|x64.ActiveCfg = AuditMode|x64 - {6BAE5851-50D5-4934-8D5E-30361A8A40F3}.AuditMode|x64.Build.0 = AuditMode|x64 - {6BAE5851-50D5-4934-8D5E-30361A8A40F3}.AuditMode|x86.ActiveCfg = AuditMode|Win32 - {6BAE5851-50D5-4934-8D5E-30361A8A40F3}.AuditMode|x86.Build.0 = AuditMode|Win32 - {6BAE5851-50D5-4934-8D5E-30361A8A40F3}.Debug|ARM64.ActiveCfg = Debug|ARM64 - {6BAE5851-50D5-4934-8D5E-30361A8A40F3}.Debug|ARM64.Build.0 = Debug|ARM64 - {6BAE5851-50D5-4934-8D5E-30361A8A40F3}.Debug|x64.ActiveCfg = Debug|x64 - {6BAE5851-50D5-4934-8D5E-30361A8A40F3}.Debug|x64.Build.0 = Debug|x64 - {6BAE5851-50D5-4934-8D5E-30361A8A40F3}.Debug|x86.ActiveCfg = Debug|Win32 - {6BAE5851-50D5-4934-8D5E-30361A8A40F3}.Debug|x86.Build.0 = Debug|Win32 - {6BAE5851-50D5-4934-8D5E-30361A8A40F3}.Fuzzing|ARM64.ActiveCfg = Fuzzing|ARM64 - {6BAE5851-50D5-4934-8D5E-30361A8A40F3}.Fuzzing|ARM64.Build.0 = Fuzzing|ARM64 - {6BAE5851-50D5-4934-8D5E-30361A8A40F3}.Fuzzing|x64.ActiveCfg = Fuzzing|x64 - {6BAE5851-50D5-4934-8D5E-30361A8A40F3}.Fuzzing|x64.Build.0 = Fuzzing|x64 - {6BAE5851-50D5-4934-8D5E-30361A8A40F3}.Fuzzing|x86.ActiveCfg = Fuzzing|Win32 - {6BAE5851-50D5-4934-8D5E-30361A8A40F3}.Fuzzing|x86.Build.0 = Fuzzing|Win32 - {6BAE5851-50D5-4934-8D5E-30361A8A40F3}.Release|ARM64.ActiveCfg = Release|ARM64 - {6BAE5851-50D5-4934-8D5E-30361A8A40F3}.Release|ARM64.Build.0 = Release|ARM64 - {6BAE5851-50D5-4934-8D5E-30361A8A40F3}.Release|x64.ActiveCfg = Release|x64 - {6BAE5851-50D5-4934-8D5E-30361A8A40F3}.Release|x64.Build.0 = Release|x64 - {6BAE5851-50D5-4934-8D5E-30361A8A40F3}.Release|x86.ActiveCfg = Release|Win32 - {6BAE5851-50D5-4934-8D5E-30361A8A40F3}.Release|x86.Build.0 = Release|Win32 {18D09A24-8240-42D6-8CB6-236EEE820263}.AuditMode|ARM64.ActiveCfg = AuditMode|ARM64 {18D09A24-8240-42D6-8CB6-236EEE820263}.AuditMode|ARM64.Build.0 = AuditMode|ARM64 {18D09A24-8240-42D6-8CB6-236EEE820263}.AuditMode|x64.ActiveCfg = AuditMode|x64 @@ -212,7 +186,6 @@ Global HideSolutionNode = FALSE EndGlobalSection GlobalSection(NestedProjects) = preSolution - {6BAE5851-50D5-4934-8D5E-30361A8A40F3} = {75AC9360-76FD-4ABC-AFEC-EF342BD2B3E9} {18D09A24-8240-42D6-8CB6-236EEE820263} = {75AC9360-76FD-4ABC-AFEC-EF342BD2B3E9} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution diff --git a/build/StoreSubmission/Preview/PDPs/de-DE/PDP.xml b/build/StoreSubmission/Preview/PDPs/de-DE/PDP.xml index 48c1ae3b94..488e9d0da7 100644 --- a/build/StoreSubmission/Preview/PDPs/de-DE/PDP.xml +++ b/build/StoreSubmission/Preview/PDPs/de-DE/PDP.xml @@ -56,7 +56,11 @@ Dies ist ein Open Source-Projekt, und wir freuen uns über die Teilnahme der Com Version __VERSION_NUMBER__ -Weitere Einzelheiten finden Sie auf der Seite der GitHub-Veröffentlichungen. +- Wir haben der Benutzeroberfläche durchschnittliche Einstellungen hinzugefügt, die nur einmal in der JSON-Datei vorhanden waren, einschließlich einer neuen Seite zum Anpassen des Layouts Ihres Menüs "Neue Registerkarte"! +- Wir haben die Fensterverwaltung zurückgesetzt, um die Zuverlässigkeit zu verbessern; Melden Sie alle Fehler, die mit dem alias "wt.exe" auftreten. +- Profile zeigen jetzt ein Symbol an, wenn sie ausgeblendet wurden oder auf programme verweisen, die deinstalliert wurden. + +Weitere Details finden Sie auf unserer GitHub-Releasesseite. diff --git a/build/StoreSubmission/Preview/PDPs/en-US/PDP.xml b/build/StoreSubmission/Preview/PDPs/en-US/PDP.xml index 9428874560..3e4fa3dbd8 100644 --- a/build/StoreSubmission/Preview/PDPs/en-US/PDP.xml +++ b/build/StoreSubmission/Preview/PDPs/en-US/PDP.xml @@ -54,7 +54,11 @@ This is an open source project and we welcome community participation. To partic - Version __VERSION_NUMBER__ + Version __VERSION_NUMBER__ + +- We've added dozens of settings to the UI that once only existed in the JSON file, including a new page for customizing the layout of your New Tab menu! +- We have rearchitected window management to improve reliability; please file any bugs you encounter with the wt.exe alias +- Profiles now show an icon if they've been hidden or refer to programs which were uninstalled. Please see our GitHub releases page for additional details. diff --git a/build/StoreSubmission/Preview/PDPs/es-ES/PDP.xml b/build/StoreSubmission/Preview/PDPs/es-ES/PDP.xml index 89b34e10ab..d93f10de27 100644 --- a/build/StoreSubmission/Preview/PDPs/es-ES/PDP.xml +++ b/build/StoreSubmission/Preview/PDPs/es-ES/PDP.xml @@ -56,7 +56,11 @@ Este es un proyecto de fuente abierta y animamos a la comunidad a participar. Pa Versión __VERSION_NUMBER__ -Para más información, consulte nuestra página de versiones de GitHub. +- Hemos agregado decenas de configuraciones a la interfaz de usuario que solo existían una vez en el archivo JSON, incluida una página nueva para personalizar el diseño del menú Nueva pestaña. +- Tenemos administración de ventanas rearchitecdas para mejorar la confiabilidad; envíe los errores que encuentre con el alias de wt.exe. +- Ahora, los perfiles muestran un icono si se han ocultado o hacen referencia a programas que se han desinstalado. + +Consulte nuestra página de versiones de GitHub para obtener más detalles. diff --git a/build/StoreSubmission/Preview/PDPs/fr-FR/PDP.xml b/build/StoreSubmission/Preview/PDPs/fr-FR/PDP.xml index fc39b6dc2b..526be4f3ba 100644 --- a/build/StoreSubmission/Preview/PDPs/fr-FR/PDP.xml +++ b/build/StoreSubmission/Preview/PDPs/fr-FR/PDP.xml @@ -54,9 +54,13 @@ Il s’agit d’un projet open source et nous vous invitons à participer dans l - Version __VERSION_NUMBER__ + __VERSION_NUMBER__ de version -Consultez la page des versions de GitHub pour plus d’informations. +- Nous avons ajouté des milliers de paramètres à l’interface utilisateur qui n’existaient auparavant que dans le fichier JSON, y compris une nouvelle page pour personnaliser la disposition de votre menu Nouvel onglet ! +- Nous avons réarchitialiser la gestion des fenêtres pour améliorer la fiabilité ; entrez les bogues rencontrés avec l’alias wt.exe +- Les profils affichent désormais une icône s’ils ont été masqués ou s’ils font référence à des programmes qui ont été désinstallés. + +Pour plus d’informations, consultez notre page des mises en production GitHub. diff --git a/build/StoreSubmission/Preview/PDPs/it-IT/PDP.xml b/build/StoreSubmission/Preview/PDPs/it-IT/PDP.xml index 1ee088dd2a..8c5ca0a25c 100644 --- a/build/StoreSubmission/Preview/PDPs/it-IT/PDP.xml +++ b/build/StoreSubmission/Preview/PDPs/it-IT/PDP.xml @@ -56,7 +56,11 @@ Si tratta di un progetto open source e la partecipazione della community è molt Versione __VERSION_NUMBER__ -Per ulteriori dettagli, consulta la nostra pagina delle versioni di GitHub. +- Sono state aggiunte decine di impostazioni all'interfaccia utente che una volta esisteva solo nel file JSON, inclusa una nuova pagina per personalizzare il layout del menu Nuova scheda. +- È stata riattivata la gestione delle finestre per migliorare l'affidabilità; inserire eventuali bug riscontrati con l'alias wt.exe +- I profili ora mostrano un'icona se sono stati nascosti o fanno riferimento ai programmi che sono stati disinstallati. + +Per altri dettagli, vedere la pagina delle versioni di GitHub. diff --git a/build/StoreSubmission/Preview/PDPs/ja-JP/PDP.xml b/build/StoreSubmission/Preview/PDPs/ja-JP/PDP.xml index 5045d6ac00..0390ceb54b 100644 --- a/build/StoreSubmission/Preview/PDPs/ja-JP/PDP.xml +++ b/build/StoreSubmission/Preview/PDPs/ja-JP/PDP.xml @@ -56,7 +56,11 @@ バージョン __VERSION_NUMBER__ -詳細については、GitHub リリースのページをご覧ください。 +- [新しいタブ] メニューのレイアウトをカスタマイズするための新しいページを含む、一度だけ JSON ファイルに存在した UI に多数の設定を追加しました。 +- 信頼性を向上させるためにウィンドウ管理を再選択しました。wt.exe エイリアスで発生したバグを報告してください +- プロファイルが非表示になっているか、アンインストールされたプログラムを参照している場合にアイコンが表示されるようになりました。 + +詳細については、GitHub リリース ページを参照してください。 diff --git a/build/StoreSubmission/Preview/PDPs/ko-KR/PDP.xml b/build/StoreSubmission/Preview/PDPs/ko-KR/PDP.xml index 6604e904d4..5ca7f5102d 100644 --- a/build/StoreSubmission/Preview/PDPs/ko-KR/PDP.xml +++ b/build/StoreSubmission/Preview/PDPs/ko-KR/PDP.xml @@ -56,6 +56,10 @@ 버전 __VERSION_NUMBER__ +- 새 탭 메뉴의 레이아웃을 사용자 지정하기 위한 새 페이지를 포함하여 JSON 파일에 한 번만 존재했던 UI에 수천 개의 설정을 추가했습니다. +- 안정성을 개선하기 위해 창 관리를 다시 보관했습니다. wt.exe 별칭에 발생한 버그를 제출하세요. +- 프로필이 숨겨졌거나 제거된 프로그램을 참조하는 경우 이제 프로필에 아이콘이 표시됩니다. + 자세한 내용은 GitHub 릴리스 페이지를 참조하세요. diff --git a/build/StoreSubmission/Preview/PDPs/pt-BR/PDP.xml b/build/StoreSubmission/Preview/PDPs/pt-BR/PDP.xml index 4e42f4dfa9..c6c84a6815 100644 --- a/build/StoreSubmission/Preview/PDPs/pt-BR/PDP.xml +++ b/build/StoreSubmission/Preview/PDPs/pt-BR/PDP.xml @@ -56,7 +56,11 @@ Este é um projeto de código aberto e a participação da comunidade é bem-vin Versão __VERSION_NUMBER__ -Consulte nossa página de lançamentos do GitHub para obter detalhes adicionais. +- Adicionamos várias configurações à interface do usuário que só existiam no arquivo JSON, incluindo uma nova página para personalizar o layout do menu Nova Guia! +- Temos o gerenciamento de janelas rearmado para melhorar a confiabilidade; registre todos os bugs encontrados com o wt.exe alias +- Os perfis agora mostram um ícone se eles foram ocultos ou se referem a programas que foram desinstalados. + +Consulte nossa página de versões do GitHub para obter detalhes adicionais. diff --git a/build/StoreSubmission/Preview/PDPs/qps-ploc/PDP.xml b/build/StoreSubmission/Preview/PDPs/qps-ploc/PDP.xml index 381718a324..e21d600da0 100644 --- a/build/StoreSubmission/Preview/PDPs/qps-ploc/PDP.xml +++ b/build/StoreSubmission/Preview/PDPs/qps-ploc/PDP.xml @@ -56,7 +56,11 @@ Vėѓѕіöй __VERSION_NUMBER__ !!! !!! ! -Рļєάśé ѕέę όüґ ĢίŧĦŭв řęļзąѕєš рαġè ƒőŗ äđδĭτíθņâℓ đέтαιľś. !!! !!! !!! !!! !!! !!! +- Ẁē'νё àðđέď đöžзńş öƒ śėŧťїńģš тб тнè ÛĮ ťħąт ŏņ¢з όⁿℓγ έжіѕŧéð іή тђε ЈŠΩŃ ƒїℓė, ĭňĉŀџđіņģ å ňэẅ φâģé ƒøя ςŭśŧŏmïżϊñģ тħέ ĺαŷöυτ öƒ убµř Йέẁ Ţàъ мęήµ! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! +- Ẁè ĥаνė řэąřčħΐŧέсτέð щįлďοш мǻňαĝēмêиť ťô ϊmрябνé ŗĕŀĩāвîĺïтγ; ρŀěăѕе ƒíŀё αⁿу вûġš ÿøú εʼnćōùлťēѓ ẃïτħ ŧћё wt.exe ǻļĭâś !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! +- Рґøƒíŀêŝ ňöẁ šћθẁ ãй ĭčöñ ίƒ ŧħэŷ'νę ъеєл ђіðδэñ őř řєƒěґ ŧσ φяοġгаmŝ ẅђíçĥ ẁ℮гέ џňϊйşťàľĺèð. !!! !!! !!! !!! !!! !!! !!! !!! !!! ! + +Рļèāŝє ŝèĕ θџŗ ĢίťĤцъ řέĺэªşэš ρąĝę ƒόř áďđїτϊōπαľ đэŧдįļŝ. !!! !!! !!! !!! !!! !!! diff --git a/build/StoreSubmission/Preview/PDPs/qps-ploca/PDP.xml b/build/StoreSubmission/Preview/PDPs/qps-ploca/PDP.xml index 381718a324..e21d600da0 100644 --- a/build/StoreSubmission/Preview/PDPs/qps-ploca/PDP.xml +++ b/build/StoreSubmission/Preview/PDPs/qps-ploca/PDP.xml @@ -56,7 +56,11 @@ Vėѓѕіöй __VERSION_NUMBER__ !!! !!! ! -Рļєάśé ѕέę όüґ ĢίŧĦŭв řęļзąѕєš рαġè ƒőŗ äđδĭτíθņâℓ đέтαιľś. !!! !!! !!! !!! !!! !!! +- Ẁē'νё àðđέď đöžзńş öƒ śėŧťїńģš тб тнè ÛĮ ťħąт ŏņ¢з όⁿℓγ έжіѕŧéð іή тђε ЈŠΩŃ ƒїℓė, ĭňĉŀџđіņģ å ňэẅ φâģé ƒøя ςŭśŧŏmïżϊñģ тħέ ĺαŷöυτ öƒ убµř Йέẁ Ţàъ мęήµ! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! +- Ẁè ĥаνė řэąřčħΐŧέсτέð щįлďοш мǻňαĝēмêиť ťô ϊmрябνé ŗĕŀĩāвîĺïтγ; ρŀěăѕе ƒíŀё αⁿу вûġš ÿøú εʼnćōùлťēѓ ẃïτħ ŧћё wt.exe ǻļĭâś !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! +- Рґøƒíŀêŝ ňöẁ šћθẁ ãй ĭčöñ ίƒ ŧħэŷ'νę ъеєл ђіðδэñ őř řєƒěґ ŧσ φяοġгаmŝ ẅђíçĥ ẁ℮гέ џňϊйşťàľĺèð. !!! !!! !!! !!! !!! !!! !!! !!! !!! ! + +Рļèāŝє ŝèĕ θџŗ ĢίťĤцъ řέĺэªşэš ρąĝę ƒόř áďđїτϊōπαľ đэŧдįļŝ. !!! !!! !!! !!! !!! !!! diff --git a/build/StoreSubmission/Preview/PDPs/qps-plocm/PDP.xml b/build/StoreSubmission/Preview/PDPs/qps-plocm/PDP.xml index 381718a324..e21d600da0 100644 --- a/build/StoreSubmission/Preview/PDPs/qps-plocm/PDP.xml +++ b/build/StoreSubmission/Preview/PDPs/qps-plocm/PDP.xml @@ -56,7 +56,11 @@ Vėѓѕіöй __VERSION_NUMBER__ !!! !!! ! -Рļєάśé ѕέę όüґ ĢίŧĦŭв řęļзąѕєš рαġè ƒőŗ äđδĭτíθņâℓ đέтαιľś. !!! !!! !!! !!! !!! !!! +- Ẁē'νё àðđέď đöžзńş öƒ śėŧťїńģš тб тнè ÛĮ ťħąт ŏņ¢з όⁿℓγ έжіѕŧéð іή тђε ЈŠΩŃ ƒїℓė, ĭňĉŀџđіņģ å ňэẅ φâģé ƒøя ςŭśŧŏmïżϊñģ тħέ ĺαŷöυτ öƒ убµř Йέẁ Ţàъ мęήµ! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! +- Ẁè ĥаνė řэąřčħΐŧέсτέð щįлďοш мǻňαĝēмêиť ťô ϊmрябνé ŗĕŀĩāвîĺïтγ; ρŀěăѕе ƒíŀё αⁿу вûġš ÿøú εʼnćōùлťēѓ ẃïτħ ŧћё wt.exe ǻļĭâś !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! +- Рґøƒíŀêŝ ňöẁ šћθẁ ãй ĭčöñ ίƒ ŧħэŷ'νę ъеєл ђіðδэñ őř řєƒěґ ŧσ φяοġгаmŝ ẅђíçĥ ẁ℮гέ џňϊйşťàľĺèð. !!! !!! !!! !!! !!! !!! !!! !!! !!! ! + +Рļèāŝє ŝèĕ θџŗ ĢίťĤцъ řέĺэªşэš ρąĝę ƒόř áďđїτϊōπαľ đэŧдįļŝ. !!! !!! !!! !!! !!! !!! diff --git a/build/StoreSubmission/Preview/PDPs/ru-RU/PDP.xml b/build/StoreSubmission/Preview/PDPs/ru-RU/PDP.xml index e944cbc595..c5c90ff6da 100644 --- a/build/StoreSubmission/Preview/PDPs/ru-RU/PDP.xml +++ b/build/StoreSubmission/Preview/PDPs/ru-RU/PDP.xml @@ -56,7 +56,11 @@ Версия __VERSION_NUMBER__ -Дополнительные сведения см. на странице «Выпуски GitHub». +- Мы добавили в пользовательский интерфейс десятки параметров, которые существовали только в JSON-файле, включая новую страницу для настройки макета меню "Новая вкладка". +- Для повышения надежности мы переупоряхлили управление окнами; создайте все ошибки, обнаруженные с wt.exe псевдонимом +- Профили теперь показывают значок, если они скрыты или ссылаются на программы, которые были удалены. + +Дополнительные сведения см. на странице выпусков GitHub. diff --git a/build/StoreSubmission/Preview/PDPs/zh-CN/PDP.xml b/build/StoreSubmission/Preview/PDPs/zh-CN/PDP.xml index e45a096a56..cd0783394c 100644 --- a/build/StoreSubmission/Preview/PDPs/zh-CN/PDP.xml +++ b/build/StoreSubmission/Preview/PDPs/zh-CN/PDP.xml @@ -56,7 +56,11 @@ 版本 __VERSION_NUMBER__ -有关其他详细信息,请参阅我们的 GitHub 发布页面。 +- 我们向用户界面添加了许多设置,这些设置仅存在于 JSON 文件中,包括用于自定义“新建标签页”菜单布局的新页面! +- 我们已重新检测窗口管理以提高可靠性;请将遇到的任何 bug 归档为 wt.exe 别名 +- 如果配置文件已隐藏或引用已卸载的程序,则它们现在将显示一个图标。 + +有关其他详细信息,请参阅 GitHub 发布页面。 diff --git a/build/StoreSubmission/Preview/PDPs/zh-TW/PDP.xml b/build/StoreSubmission/Preview/PDPs/zh-TW/PDP.xml index 40e469d9e9..eeec299d96 100644 --- a/build/StoreSubmission/Preview/PDPs/zh-TW/PDP.xml +++ b/build/StoreSubmission/Preview/PDPs/zh-TW/PDP.xml @@ -56,7 +56,11 @@ 版本 __VERSION_NUMBER__ -如需詳細資訊,請參閱我們的 GitHub 版本頁面。 +- 我們已新增數十個只存在於 JSON 檔案中的設定到 UI,包括自定義 [新索引標籤] 功能表版面配置的新頁面! +- 我們已重新設定視窗管理,以改善可靠性;請提出您在 wt.exe 別名遇到的任何錯誤 +- 設定文件現在會在隱藏或參照已卸載的程式時顯示圖示。 + +如需詳細數據,請參閱我們的 GitHub 版本頁面。 diff --git a/build/StoreSubmission/Stable/PDPs/de-DE/PDP.xml b/build/StoreSubmission/Stable/PDPs/de-DE/PDP.xml index 815909966d..47ff614bd0 100644 --- a/build/StoreSubmission/Stable/PDPs/de-DE/PDP.xml +++ b/build/StoreSubmission/Stable/PDPs/de-DE/PDP.xml @@ -56,7 +56,14 @@ Dies ist ein Open Source-Projekt, und wir freuen uns über die Teilnahme an der Version __VERSION_NUMBER__ -Weitere Einzelheiten finden Sie auf der Seite der GitHub-Veröffentlichungen. +– Wir haben umgeschrieben, wie Konsolenanwendungen im Terminal gehostet werden! Melden Sie alle auftretenden Fehler. +– Terminal unterstützt jetzt Sixels! +– Sie können jetzt einen angedockten Bereich öffnen, der Ausschnitte von Befehlen enthält, die Sie gespeichert haben, um sie später zu verwenden. +– Für Benutzer der Eingabeaufforderung der neuesten Version von Windows 11 wird möglicherweise ein QuickInfo-Symbol angezeigt, das installierbare Software von WinGet vorschlägt. +– Ausgewählter Text wird jetzt viel sichtbarer (und anpassbarer!). +- Eine Reihe von Zuverlässigkeitsfehlern, Benutzerfreundlichkeitsproblemen und Ärgernissen wurden behoben. + +Weitere Informationen finden Sie auf unserer GitHub-Releaseseite. diff --git a/build/StoreSubmission/Stable/PDPs/en-US/PDP.xml b/build/StoreSubmission/Stable/PDPs/en-US/PDP.xml index 7468f319e5..993c27e011 100644 --- a/build/StoreSubmission/Stable/PDPs/en-US/PDP.xml +++ b/build/StoreSubmission/Stable/PDPs/en-US/PDP.xml @@ -56,6 +56,13 @@ This is an open source project and we welcome community participation. To partic Version __VERSION_NUMBER__ +- We've rewritten how console applications are hosted inside Terminal! Please report any bugs you encounter. +- Terminal now supports Sixels! +- You can now open a docked panel containing snippets of commands you have saved to use later +- Command Prompt users on the latest Windows 11 release may see a "quick tip" icon that suggests installable software from WinGet +- Selected text will now be much more visible (and customizable!) +- A number of reliabilty bugs, convenience issues and annoyances have been fixed. + Please see our GitHub releases page for additional details. diff --git a/build/StoreSubmission/Stable/PDPs/es-ES/PDP.xml b/build/StoreSubmission/Stable/PDPs/es-ES/PDP.xml index 2be0f94dd3..84bd2cc399 100644 --- a/build/StoreSubmission/Stable/PDPs/es-ES/PDP.xml +++ b/build/StoreSubmission/Stable/PDPs/es-ES/PDP.xml @@ -56,7 +56,14 @@ Este es un proyecto de fuente abierta y animamos a la comunidad a participar. Pa Versión __VERSION_NUMBER__ -Para más información, consulte nuestra página de versiones de GitHub. +- Hemos reescrito cómo se hospedan las aplicaciones de consola en Terminal. Informe de los errores que encuentre. +- Terminal ahora admite síxeles. +- Ahora puede abrir un panel acoplado que contenga fragmentos de comandos que haya guardado para usarlos más adelante +- Los usuarios del símbolo del sistema de la versión más reciente de Windows 11 pueden ver un icono de "sugerencia rápida" que sugiere software instalable de WinGet +- El texto seleccionado ahora será mucho más visible (y personalizable) +- Se han corregido varios errores de fiabilidad, problemas de comodidad y molestias. + +Consulte la página de versiones de GitHub para más información. diff --git a/build/StoreSubmission/Stable/PDPs/fr-FR/PDP.xml b/build/StoreSubmission/Stable/PDPs/fr-FR/PDP.xml index 59168e815c..34c6a13ea8 100644 --- a/build/StoreSubmission/Stable/PDPs/fr-FR/PDP.xml +++ b/build/StoreSubmission/Stable/PDPs/fr-FR/PDP.xml @@ -56,7 +56,14 @@ Il s’agit d’un projet open source et nous encourageons la participation à l Version __VERSION_NUMBER__ -Consultez la page des versions de GitHub pour plus d’informations. +– Nous avons réécrit la manière dont les applications de console sont hébergées dans Terminal ! Veuillez signaler tout bogue que vous rencontrez. +– Terminal prend désormais en charge Sixels ! +– Vous pouvez maintenant ouvrir un panneau ancré contenant des extraits de commandes que vous avez enregistrées pour les utiliser ultérieurement +– Les utilisateurs de l’invite de commande sur la dernière version de Windows 11 peuvent voir une icône « astuce rapide » qui suggère un logiciel installable à partir de WinGet +– Le texte sélectionné sera désormais beaucoup plus visible (et personnalisable !) +– Un certain nombre de bogues de fiabilité, de problèmes de commodité et de désagréments ont été corrigés. + +Veuillez consulter notre page des versions GitHub pour découvrir d’autres détails. diff --git a/build/StoreSubmission/Stable/PDPs/it-IT/PDP.xml b/build/StoreSubmission/Stable/PDPs/it-IT/PDP.xml index 4d15d3f899..9d7ce218e8 100644 --- a/build/StoreSubmission/Stable/PDPs/it-IT/PDP.xml +++ b/build/StoreSubmission/Stable/PDPs/it-IT/PDP.xml @@ -56,7 +56,14 @@ Si tratta di un progetto open source e la partecipazione della community è molt Versione __VERSION_NUMBER__ -Per ulteriori dettagli, consulta la nostra pagina delle versioni di GitHub. +- Abbiamo cambiato il modo in cui le applicazioni della console vengono ospitate all’interno di Terminale. Segnala eventuali bug riscontrati. +- Ora Terminale supporta i Sixel. +- Puoi aprire un pannello ancorato contenente frammenti di comandi salvati per usarli in seguito +- Gli utenti che usano il prompt dei comandi nella versione più recente di Windows 11 potrebbero visualizzare un’icona di “suggerimento rapido” che consiglia il software installabile da WinGet +- Il testo selezionato sarà ora molto più visibile, oltre che personalizzabile. +- Sono stati risolti diversi bug di affidabilità e problemi di ordine pratico. + +Per altri dettagli, vedi la pagina delle release di GitHub. diff --git a/build/StoreSubmission/Stable/PDPs/ja-JP/PDP.xml b/build/StoreSubmission/Stable/PDPs/ja-JP/PDP.xml index dda6bf9bd0..27a38762bb 100644 --- a/build/StoreSubmission/Stable/PDPs/ja-JP/PDP.xml +++ b/build/StoreSubmission/Stable/PDPs/ja-JP/PDP.xml @@ -56,7 +56,14 @@ バージョン __VERSION_NUMBER__ -詳細については、GitHub リリースのページをご覧ください。 +- ターミナル内でのコンソール アプリケーションのホスト方法を書き換えました。発生したバグを報告してください。 +- ターミナルで Sixels がサポートされるようになりました。 +- 後で使用するために保存したコマンドのスニペットを含むドッキング パネルを開けるようになりました +- 最新の Windows 11 リリースのコマンド プロンプト ユーザーには、WinGet からインストール可能なソフトウェアを提案する "クイック ヒント" アイコンが表示される場合があります +- 選択したテキストが大幅に見やすくなりました (カスタマイズも可能です) +- 信頼性に関するバグ、利便性の問題、不快な問題の多くが修正されました。 + +詳細については、GitHub リリース ページをご覧ください。 diff --git a/build/StoreSubmission/Stable/PDPs/ko-KR/PDP.xml b/build/StoreSubmission/Stable/PDPs/ko-KR/PDP.xml index ae0cddc3e0..8dac845667 100644 --- a/build/StoreSubmission/Stable/PDPs/ko-KR/PDP.xml +++ b/build/StoreSubmission/Stable/PDPs/ko-KR/PDP.xml @@ -56,6 +56,13 @@ 버전 __VERSION_NUMBER__ +- 콘솔 애플리케이션이 터미널 내에서 호스팅되는 방법을 다시 작성했습니다. 버그가 발생하면 보고해 주세요. +- 터미널에서 이제 Sixels를 지원합니다. +- 이제 나중에 사용하기 위해 저장한 명령 조각이 포함된 도킹된 패널을 열 수 있습니다. +- 최신 Windows 11 릴리스의 명령 프롬프트 사용자는 WinGet에서 설치 가능한 소프트웨어를 추천하는 "간단한 팁" 아이콘을 볼 수 있습니다. +- 이제 선택한 텍스트가 훨씬 더 잘 보입니다(사용자 지정 가능). +- 여러 안정성 버그, 편의성 문제, 불편 사항이 수정되었습니다. + 자세한 내용은 GitHub 릴리스 페이지를 참조하세요. diff --git a/build/StoreSubmission/Stable/PDPs/pt-BR/PDP.xml b/build/StoreSubmission/Stable/PDPs/pt-BR/PDP.xml index ca64b4b9d3..cd3b5ce368 100644 --- a/build/StoreSubmission/Stable/PDPs/pt-BR/PDP.xml +++ b/build/StoreSubmission/Stable/PDPs/pt-BR/PDP.xml @@ -56,7 +56,14 @@ Este é um projeto de código aberto e a participação da comunidade é bem-vin Versão __VERSION_NUMBER__ -Consulte nossa página de lançamentos do GitHub para obter detalhes adicionais. +– Reescrevemos a forma como os aplicativos de console são hospedados no Terminal! Relate os bugs encontrados. +– O terminal agora oferece suporte ao Sixels! +– Agora você pode abrir um painel acoplado contendo snippets de comandos que você salvou para usar mais tarde +– Os usuários do Prompt de Comando na versão mais recente do Windows 11 podem ver um ícone de "dica rápida", que sugere softwares instaláveis a partir do WinGet +– O texto selecionado agora ficará muito mais visível (e personalizável!) +– Vários bugs de confiabilidade, problemas de conveniência e incômodos foram resolvidos. + +Confira nossa página de lançamentos no GitHub para obter mais detalhes. diff --git a/build/StoreSubmission/Stable/PDPs/qps-ploc/PDP.xml b/build/StoreSubmission/Stable/PDPs/qps-ploc/PDP.xml index 0156522a9e..d911bbd69b 100644 --- a/build/StoreSubmission/Stable/PDPs/qps-ploc/PDP.xml +++ b/build/StoreSubmission/Stable/PDPs/qps-ploc/PDP.xml @@ -56,7 +56,14 @@ Vėѓѕіöй __VERSION_NUMBER__ !!! !!! ! -Рļєάśé ѕέę όüґ ĢίŧĦŭв řęļзąѕєš рαġè ƒőŗ äđδĭτíθņâℓ đέтαιľś. !!! !!! !!! !!! !!! !!! +- Ẁē'νё ŕéẁѓĭτťёñ ћοώ ĉòπşõℓε άррℓіċªťįõпѕ αяе ĥθѕťэđ įŋšιďé Ţєямїńąℓ! Рļéаšė яёροřτ αņу ьϋģš ýõμ éпćŏџήţęя. !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !! +- Ţëямΐʼnαļ ńóẃ ŝüррöятš Śїхέłś! !!! !!! !!! +- ¥оų ĉåи ńòŵ θρėñ д đбčĸэď ράńέļ ċőлŧăīņϊňģ śⁿіφφëťś оƒ ςōмmàⁿďş ŷŏũ ĥªν℮ şåνěđ τσ üśε łαťэŗ !!! !!! !!! !!! !!! !!! !!! !!! !!! +- Ćοмmäлđ Рřōmφť üş℮ŗѕ öη τће ļāťëšτ Щīйđôώѕ 11 řёℓеаѕĕ måў ŝэε ά "qůïςκ ŧĭр" ιсôñ τĥдт šűğģєѕŧѕ ίńśŧăłłавļз šôƒţẁαгέ ƒґόm ЩĩйĞéţ !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! +- Śєļèċťєď ţĕжт ωϊŀļ йǿẃ ьέ mџ¢н мǿѓε νĭŝϊъļė (άŋđ сŭŝтŏмΐżдьļē!) !!! !!! !!! !!! !!! !!! ! +- Ä ņϋmъ℮ŗ ŏƒ ѓēŀїаъïļŧÿ ьüĝś, ςôⁿνėηĭ℮иć℮ îѕšůëş ăπð âлňбγдňçėŝ ћªνε ъēёп ƒΐ×еð. !!! !!! !!! !!! !!! !!! !!! !!! + +Ρĺёàŝ℮ ŝез ǿúг ĢīťНŭъ řěłεαśèŝ φāğ℮ ƒóѓ дďδітĭøиąℓ ð℮тªїľŝ. !!! !!! !!! !!! !!! !!! diff --git a/build/StoreSubmission/Stable/PDPs/qps-ploca/PDP.xml b/build/StoreSubmission/Stable/PDPs/qps-ploca/PDP.xml index 0156522a9e..d911bbd69b 100644 --- a/build/StoreSubmission/Stable/PDPs/qps-ploca/PDP.xml +++ b/build/StoreSubmission/Stable/PDPs/qps-ploca/PDP.xml @@ -56,7 +56,14 @@ Vėѓѕіöй __VERSION_NUMBER__ !!! !!! ! -Рļєάśé ѕέę όüґ ĢίŧĦŭв řęļзąѕєš рαġè ƒőŗ äđδĭτíθņâℓ đέтαιľś. !!! !!! !!! !!! !!! !!! +- Ẁē'νё ŕéẁѓĭτťёñ ћοώ ĉòπşõℓε άррℓіċªťįõпѕ αяе ĥθѕťэđ įŋšιďé Ţєямїńąℓ! Рļéаšė яёροřτ αņу ьϋģš ýõμ éпćŏџήţęя. !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !! +- Ţëямΐʼnαļ ńóẃ ŝüррöятš Śїхέłś! !!! !!! !!! +- ¥оų ĉåи ńòŵ θρėñ д đбčĸэď ράńέļ ċőлŧăīņϊňģ śⁿіφφëťś оƒ ςōмmàⁿďş ŷŏũ ĥªν℮ şåνěđ τσ üśε łαťэŗ !!! !!! !!! !!! !!! !!! !!! !!! !!! +- Ćοмmäлđ Рřōmφť üş℮ŗѕ öη τће ļāťëšτ Щīйđôώѕ 11 řёℓеаѕĕ måў ŝэε ά "qůïςκ ŧĭр" ιсôñ τĥдт šűğģєѕŧѕ ίńśŧăłłавļз šôƒţẁαгέ ƒґόm ЩĩйĞéţ !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! +- Śєļèċťєď ţĕжт ωϊŀļ йǿẃ ьέ mџ¢н мǿѓε νĭŝϊъļė (άŋđ сŭŝтŏмΐżдьļē!) !!! !!! !!! !!! !!! !!! ! +- Ä ņϋmъ℮ŗ ŏƒ ѓēŀїаъïļŧÿ ьüĝś, ςôⁿνėηĭ℮иć℮ îѕšůëş ăπð âлňбγдňçėŝ ћªνε ъēёп ƒΐ×еð. !!! !!! !!! !!! !!! !!! !!! !!! + +Ρĺёàŝ℮ ŝез ǿúг ĢīťНŭъ řěłεαśèŝ φāğ℮ ƒóѓ дďδітĭøиąℓ ð℮тªїľŝ. !!! !!! !!! !!! !!! !!! diff --git a/build/StoreSubmission/Stable/PDPs/qps-plocm/PDP.xml b/build/StoreSubmission/Stable/PDPs/qps-plocm/PDP.xml index 0156522a9e..d911bbd69b 100644 --- a/build/StoreSubmission/Stable/PDPs/qps-plocm/PDP.xml +++ b/build/StoreSubmission/Stable/PDPs/qps-plocm/PDP.xml @@ -56,7 +56,14 @@ Vėѓѕіöй __VERSION_NUMBER__ !!! !!! ! -Рļєάśé ѕέę όüґ ĢίŧĦŭв řęļзąѕєš рαġè ƒőŗ äđδĭτíθņâℓ đέтαιľś. !!! !!! !!! !!! !!! !!! +- Ẁē'νё ŕéẁѓĭτťёñ ћοώ ĉòπşõℓε άррℓіċªťįõпѕ αяе ĥθѕťэđ įŋšιďé Ţєямїńąℓ! Рļéаšė яёροřτ αņу ьϋģš ýõμ éпćŏџήţęя. !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !! +- Ţëямΐʼnαļ ńóẃ ŝüррöятš Śїхέłś! !!! !!! !!! +- ¥оų ĉåи ńòŵ θρėñ д đбčĸэď ράńέļ ċőлŧăīņϊňģ śⁿіφφëťś оƒ ςōмmàⁿďş ŷŏũ ĥªν℮ şåνěđ τσ üśε łαťэŗ !!! !!! !!! !!! !!! !!! !!! !!! !!! +- Ćοмmäлđ Рřōmφť üş℮ŗѕ öη τће ļāťëšτ Щīйđôώѕ 11 řёℓеаѕĕ måў ŝэε ά "qůïςκ ŧĭр" ιсôñ τĥдт šűğģєѕŧѕ ίńśŧăłłавļз šôƒţẁαгέ ƒґόm ЩĩйĞéţ !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! !!! +- Śєļèċťєď ţĕжт ωϊŀļ йǿẃ ьέ mџ¢н мǿѓε νĭŝϊъļė (άŋđ сŭŝтŏмΐżдьļē!) !!! !!! !!! !!! !!! !!! ! +- Ä ņϋmъ℮ŗ ŏƒ ѓēŀїаъïļŧÿ ьüĝś, ςôⁿνėηĭ℮иć℮ îѕšůëş ăπð âлňбγдňçėŝ ћªνε ъēёп ƒΐ×еð. !!! !!! !!! !!! !!! !!! !!! !!! + +Ρĺёàŝ℮ ŝез ǿúг ĢīťНŭъ řěłεαśèŝ φāğ℮ ƒóѓ дďδітĭøиąℓ ð℮тªїľŝ. !!! !!! !!! !!! !!! !!! diff --git a/build/StoreSubmission/Stable/PDPs/ru-RU/PDP.xml b/build/StoreSubmission/Stable/PDPs/ru-RU/PDP.xml index 9ac0a14058..011e5152d7 100644 --- a/build/StoreSubmission/Stable/PDPs/ru-RU/PDP.xml +++ b/build/StoreSubmission/Stable/PDPs/ru-RU/PDP.xml @@ -56,7 +56,14 @@ Версия __VERSION_NUMBER__ -Дополнительные сведения см. на странице «Выпуски GitHub». +– Мы переписали, как консольные приложения размещаются внутри Терминала! Сообщайте о любых ошибках, с которыми вы столкнулись. +– Терминал теперь поддерживает форматы Sixel! +– Теперь вы можете открыть закрепленную панель, содержащую фрагменты команд, которые вы сохранили для использования в дальнейшем +– Пользователи командной строки в новейшем выпуске Windows 11 могут увидеть значок "краткой подсказки", который предлагает устанавливаемые программы из WinGet +– Выделенный текст теперь станет более видимым (и настраиваемым!) +– Исправлено несколько ошибок надежности, проблем с удобством, а также устранены раздражающие моменты. + +Дополнительные сведения см. на странице выпусков GitHub. diff --git a/build/StoreSubmission/Stable/PDPs/zh-CN/PDP.xml b/build/StoreSubmission/Stable/PDPs/zh-CN/PDP.xml index 8bf387c150..21db7d2c3d 100644 --- a/build/StoreSubmission/Stable/PDPs/zh-CN/PDP.xml +++ b/build/StoreSubmission/Stable/PDPs/zh-CN/PDP.xml @@ -54,7 +54,14 @@ - 版本 __VERSION_NUMBER__ + Version __VERSION_NUMBER__ + +- 我们已改变主机应用程序在终端内的托管方式!请报告遇到的任何 bug。 +- 终端现在支持 Sixels! +- 现在可以打开一个停靠面板,其中包含已保存供以后使用的命令片段 +- 最新 Windows 11 版本上的命令提示用户可能会看到“快速提示”图标,该图标建议从 WinGet 安装软件 +- 所选文本现在将具有更高的可见性(和可自定义性!) +- 修复了许多可靠性 bug、便利性问题和令人烦恼的问题。 有关其他详细信息,请参阅我们的 GitHub 发布页面。 diff --git a/build/StoreSubmission/Stable/PDPs/zh-TW/PDP.xml b/build/StoreSubmission/Stable/PDPs/zh-TW/PDP.xml index f0c7d4017f..02e5b69a3c 100644 --- a/build/StoreSubmission/Stable/PDPs/zh-TW/PDP.xml +++ b/build/StoreSubmission/Stable/PDPs/zh-TW/PDP.xml @@ -56,7 +56,14 @@ 版本 __VERSION_NUMBER__ -如需詳細資訊,請參閱我們的 GitHub 版本頁面。 +- 我們已重寫主機應用程式在終端機內託管的方式!請報告您遇到的錯誤。 +- 終端機現在支援 Sixels! +- 現在,您可以開啟包含已儲存命令程式碼片段的固定面板,以供稍後使用 +- 最新 Windows 11 版本中的 [命令提示] 使用者可能會看到「快速提示」圖示,建議可自 WinGet 安裝的軟體 +- 選取的文字現在會更明顯 (且可自訂!) +- 已修正一些可靠性錯誤、便利性問題和令人困擾的問題。 + +如需更多詳細資訊,請參閱我們的 GitHub 發行頁面。 diff --git a/build/config/272MSSharedLibSN2048.snk b/build/config/272MSSharedLibSN2048.snk new file mode 100644 index 0000000000..bd766f84a2 Binary files /dev/null and b/build/config/272MSSharedLibSN2048.snk differ diff --git a/build/config/esrp.build.batch.wpfdotnet.json b/build/config/esrp.build.batch.wpfdotnet.json index 0699353f64..316aa70116 100644 --- a/build/config/esrp.build.batch.wpfdotnet.json +++ b/build/config/esrp.build.batch.wpfdotnet.json @@ -6,6 +6,20 @@ ], "SigningInfo": { "Operations": [ + { + "KeyCode": "CP-233904-SN", + "OperationSetCode": "StrongNameSign", + "ToolName": "sign", + "ToolVersion": "1.0", + "Parameters": [] + }, + { + "KeyCode": "CP-233904-SN", + "OperationSetCode": "StrongNameVerify", + "ToolName": "sign", + "ToolVersion": "1.0", + "Parameters": [] + }, { "KeyCode": "CP-230012", "OperationSetCode": "SigntoolSign", diff --git a/build/config/tsa.json b/build/config/tsa.json index 89874d37fc..61924ef4bd 100644 --- a/build/config/tsa.json +++ b/build/config/tsa.json @@ -1,6 +1,6 @@ { "instanceUrl": "https://microsoft.visualstudio.com", "projectName": "OS", - "areaPath": "OS\\Windows Client and Services\\ADEPT\\E4D-Engineered for Developers\\SHINE\\Terminal", + "areaPath": "OS\\Windows Client and Services\\WinPD\\DFX-Developer Fundamentals and Experiences\\DEFT\\SHINE\\Terminal", "notificationAliases": ["condev@microsoft.com", "duhowett@microsoft.com"] } diff --git a/build/packages.config b/build/packages.config index ceadd04ac2..3572da0e54 100644 --- a/build/packages.config +++ b/build/packages.config @@ -1,7 +1,6 @@ - - + diff --git a/build/pipelines/daily-loc-submission.yml b/build/pipelines/daily-loc-submission.yml index 403501ed32..7fddafa6cc 100644 --- a/build/pipelines/daily-loc-submission.yml +++ b/build/pipelines/daily-loc-submission.yml @@ -47,7 +47,7 @@ steps: git config --local core.autocrlf true displayName: Prepare git submission environment -- task: MicrosoftTDBuild.tdbuild-task.tdbuild-task.TouchdownBuildTask@3 +- task: MicrosoftTDBuild.tdbuild-task.tdbuild-task.TouchdownBuildTask@5 displayName: 'Touchdown Build - 7105, PRODEXT' inputs: teamId: 7105 diff --git a/build/pipelines/ob-nightly.yml b/build/pipelines/ob-nightly.yml index 18a1a1ddec..033d075cd6 100644 --- a/build/pipelines/ob-nightly.yml +++ b/build/pipelines/ob-nightly.yml @@ -28,7 +28,7 @@ extends: official: true branding: Canary buildTerminal: true - pgoBuildMode: Optimize + pgoBuildMode: None # BODGY - OneBranch is on VS 17.10, which is known to be the worst codeSign: true signingIdentity: serviceName: $(SigningServiceName) @@ -37,6 +37,8 @@ extends: akvName: $(SigningAKVName) authCertName: $(SigningAuthCertName) signCertName: $(SigningSignCertName) + useManagedIdentity: $(SigningUseManagedIdentity) + clientId: $(SigningOriginalClientId) publishSymbolsToPublic: true publishVpackToWindows: false symbolExpiryTime: 15 diff --git a/build/pipelines/ob-release.yml b/build/pipelines/ob-release.yml index 7ae0e71d06..d7de0e0a3a 100644 --- a/build/pipelines/ob-release.yml +++ b/build/pipelines/ob-release.yml @@ -27,7 +27,7 @@ parameters: - name: pgoBuildMode displayName: "PGO Build Mode" type: string - default: Optimize + default: None # BODGY - OneBranch is on VS 17.10, which is known to be the worst values: - Optimize - Instrument @@ -85,6 +85,8 @@ extends: akvName: $(SigningAKVName) authCertName: $(SigningAuthCertName) signCertName: $(SigningSignCertName) + useManagedIdentity: $(SigningUseManagedIdentity) + clientId: $(SigningOriginalClientId) terminalInternalPackageVersion: ${{ parameters.terminalInternalPackageVersion }} publishSymbolsToPublic: ${{ parameters.publishSymbolsToPublic }} publishVpackToWindows: ${{ parameters.publishVpackToWindows }} diff --git a/build/pipelines/templates-v2/job-build-package-wpf.yml b/build/pipelines/templates-v2/job-build-package-wpf.yml index dd547502e7..a1f44373d0 100644 --- a/build/pipelines/templates-v2/job-build-package-wpf.yml +++ b/build/pipelines/templates-v2/job-build-package-wpf.yml @@ -59,10 +59,7 @@ jobs: submodules: true persistCredentials: True - - task: PkgESSetupBuild@12 - displayName: Package ES - Setup Build - inputs: - disableOutputRedirect: true + - template: steps-setup-versioning.yml - template: steps-download-bin-dir-artifact.yml parameters: diff --git a/build/pipelines/templates-v2/job-build-project.yml b/build/pipelines/templates-v2/job-build-project.yml index ac350da72f..47390bbbf3 100644 --- a/build/pipelines/templates-v2/job-build-project.yml +++ b/build/pipelines/templates-v2/job-build-project.yml @@ -159,6 +159,8 @@ jobs: .\build\scripts\Generate-ThirdPartyNotices.ps1 -MarkdownNoticePath .\NOTICE.md -OutputPath .\src\cascadia\CascadiaPackage\NOTICE.html displayName: Generate NOTICE.html from NOTICE.md + - template: .\steps-install-vcpkg.yml + - template: .\steps-restore-nuget.yml - pwsh: |- diff --git a/build/pipelines/templates-v2/job-check-code-format.yml b/build/pipelines/templates-v2/job-check-code-format.yml index e889fc8756..c26b7f8aca 100644 --- a/build/pipelines/templates-v2/job-check-code-format.yml +++ b/build/pipelines/templates-v2/job-check-code-format.yml @@ -10,6 +10,6 @@ jobs: submodules: false clean: true - - powershell: |- + - pwsh: |- .\build\scripts\Invoke-FormattingCheck.ps1 displayName: 'Run formatters' diff --git a/build/pipelines/templates-v2/job-deploy-to-azure-storage.yml b/build/pipelines/templates-v2/job-deploy-to-azure-storage.yml index e2ed380fd4..8c2836c059 100644 --- a/build/pipelines/templates-v2/job-deploy-to-azure-storage.yml +++ b/build/pipelines/templates-v2/job-deploy-to-azure-storage.yml @@ -75,18 +75,13 @@ jobs: } displayName: "Wrangle Unpackaged builds into place, rename" - - powershell: |- - Get-PackageProvider -Name NuGet -ForceBootstrap - Install-Module -Verbose -AllowClobber -Force Az.Accounts, Az.Storage, Az.Network, Az.Resources, Az.Compute - displayName: Install Azure Module Dependencies - - - task: AzureFileCopy@6 + - task: AzurePowerShell@5 displayName: Publish to Storage Account inputs: - sourcePath: _out/* - Destination: AzureBlob azureSubscription: ${{ parameters.subscription }} - storage: ${{ parameters.storageAccount }} - ContainerName: ${{ parameters.storageContainer }} - AdditionalArgumentsForBlobCopy: "--content-type application/octet-stream" - + azurePowerShellVersion: LatestVersion + pwsh: true + ScriptType: InlineScript + Inline: |- + $Env:AZCOPY_AUTO_LOGIN_TYPE="PSCRED" + & AzCopy copy "_out\*" "https://${{ parameters.storageAccount }}.blob.core.windows.net/${{ parameters.storageContainer }}/" --content-type application/octet-stream diff --git a/build/pipelines/templates-v2/job-merge-msix-into-bundle.yml b/build/pipelines/templates-v2/job-merge-msix-into-bundle.yml index f400e2cb12..261750db8f 100644 --- a/build/pipelines/templates-v2/job-merge-msix-into-bundle.yml +++ b/build/pipelines/templates-v2/job-merge-msix-into-bundle.yml @@ -69,10 +69,9 @@ jobs: fetchTags: false # Tags still result in depth > 1 fetch; we don't need them here submodules: true persistCredentials: True - - task: PkgESSetupBuild@12 - displayName: Package ES - Setup Build - inputs: - disableOutputRedirect: true + + - template: steps-setup-versioning.yml + - template: steps-download-bin-dir-artifact.yml parameters: buildPlatforms: ${{ parameters.buildPlatforms }} @@ -148,6 +147,10 @@ jobs: ValidateSignature: true Verbosity: 'Verbose' + - pwsh: |- + tar -c -v --format=zip -f "$(JobOutputDirectory)/GroupPolicyTemplates_$(XES_APPXMANIFESTVERSION).zip" -C "$(Build.SourcesDirectory)/policies" * + displayName: Package GPO Templates + - ${{ parameters.afterBuildSteps }} - ${{ if eq(parameters.publishArtifacts, true) }}: diff --git a/build/pipelines/templates-v2/job-package-conpty.yml b/build/pipelines/templates-v2/job-package-conpty.yml index 303bb998f5..b91c2989f3 100644 --- a/build/pipelines/templates-v2/job-package-conpty.yml +++ b/build/pipelines/templates-v2/job-package-conpty.yml @@ -57,10 +57,7 @@ jobs: submodules: true persistCredentials: True - - task: PkgESSetupBuild@12 - displayName: Package ES - Setup Build - inputs: - disableOutputRedirect: true + - template: steps-setup-versioning.yml - template: steps-download-bin-dir-artifact.yml parameters: diff --git a/build/pipelines/templates-v2/job-publish-symbols-using-symbolrequestprod-api.yml b/build/pipelines/templates-v2/job-publish-symbols-using-symbolrequestprod-api.yml index 0f9d338699..a5ed41f737 100644 --- a/build/pipelines/templates-v2/job-publish-symbols-using-symbolrequestprod-api.yml +++ b/build/pipelines/templates-v2/job-publish-symbols-using-symbolrequestprod-api.yml @@ -44,10 +44,7 @@ jobs: submodules: true persistCredentials: True - - task: PkgESSetupBuild@12 - displayName: Package ES - Setup Build - inputs: - disableOutputRedirect: true + - template: steps-setup-versioning.yml - task: DownloadPipelineArtifact@2 displayName: Download all PDBs from all prior build phases @@ -55,11 +52,6 @@ jobs: itemPattern: '**/*.pdb' targetPath: '$(Build.SourcesDirectory)/bin' - - powershell: |- - Get-PackageProvider -Name NuGet -ForceBootstrap - Install-Module -Verbose -AllowClobber -Force Az.Accounts, Az.Storage, Az.Network, Az.Resources, Az.Compute - displayName: Install Azure Module Dependencies - # Transit the Azure token from the Service Connection into a secret variable for the rest of the pipeline to use. - task: AzurePowerShell@5 displayName: Generate an Azure Token diff --git a/build/pipelines/templates-v2/job-publish-symbols.yml b/build/pipelines/templates-v2/job-publish-symbols.yml index 83c472872b..7f86c2f1b2 100644 --- a/build/pipelines/templates-v2/job-publish-symbols.yml +++ b/build/pipelines/templates-v2/job-publish-symbols.yml @@ -43,10 +43,7 @@ jobs: submodules: true persistCredentials: True - - task: PkgESSetupBuild@12 - displayName: Package ES - Setup Build - inputs: - disableOutputRedirect: true + - template: steps-setup-versioning.yml - task: DownloadPipelineArtifact@2 displayName: Download all PDBs from all prior build phases diff --git a/build/pipelines/templates-v2/job-submit-windows-vpack.yml b/build/pipelines/templates-v2/job-submit-windows-vpack.yml index 2e9cb1e1fe..20c2aaa9f2 100644 --- a/build/pipelines/templates-v2/job-submit-windows-vpack.yml +++ b/build/pipelines/templates-v2/job-submit-windows-vpack.yml @@ -38,10 +38,7 @@ jobs: submodules: true persistCredentials: True - - task: PkgESSetupBuild@12 - displayName: Package ES - Setup Build - inputs: - disableOutputRedirect: true + - template: steps-setup-versioning.yml - task: DownloadPipelineArtifact@2 displayName: Download MSIX Bundle Artifact diff --git a/build/pipelines/templates-v2/pipeline-full-release-build.yml b/build/pipelines/templates-v2/pipeline-full-release-build.yml index d2a32c8c46..8651f54568 100644 --- a/build/pipelines/templates-v2/pipeline-full-release-build.yml +++ b/build/pipelines/templates-v2/pipeline-full-release-build.yml @@ -92,10 +92,7 @@ stages: generateSbom: ${{ parameters.generateSbom }} codeSign: ${{ parameters.codeSign }} beforeBuildSteps: # Right before we build, lay down the universal package and localizations - - task: PkgESSetupBuild@12 - displayName: Package ES - Setup Build - inputs: - disableOutputRedirect: true + - template: ./build/pipelines/templates-v2/steps-setup-versioning.yml@self - task: UniversalPackages@0 displayName: Download terminal-internal Universal Package @@ -119,10 +116,7 @@ stages: generateSbom: ${{ parameters.generateSbom }} codeSign: ${{ parameters.codeSign }} beforeBuildSteps: - - task: PkgESSetupBuild@12 - displayName: Package ES - Setup Build - inputs: - disableOutputRedirect: true + - template: ./build/pipelines/templates-v2/steps-setup-versioning.yml@self # WPF doesn't need the localizations or the universal package, but if it does... put them here. - stage: Package diff --git a/build/pipelines/templates-v2/pipeline-onebranch-full-release-build.yml b/build/pipelines/templates-v2/pipeline-onebranch-full-release-build.yml index be5cbaca78..0f09271a72 100644 --- a/build/pipelines/templates-v2/pipeline-onebranch-full-release-build.yml +++ b/build/pipelines/templates-v2/pipeline-onebranch-full-release-build.yml @@ -78,7 +78,9 @@ extends: template: v2/Microsoft.NonOfficial.yml@templates parameters: featureFlags: - WindowsHostVersion: 1ESWindows2022 + WindowsHostVersion: + Version: 2022 + Network: R1 platform: name: 'windows_undocked' product: 'Windows Terminal' @@ -106,11 +108,6 @@ extends: - stage: Build displayName: Build dependsOn: [] - variables: - # This was set by the parent build, but we need to override it to select a specific compiler version - - template: ./build/pipelines/templates-v2/variables-onebranch-config.yml@self - parameters: - containerVersion: 1.0.02566.28 jobs: - template: ./build/pipelines/templates-v2/job-build-project.yml@self parameters: @@ -135,10 +132,7 @@ extends: codeSign: ${{ parameters.codeSign }} signingIdentity: ${{ parameters.signingIdentity }} beforeBuildSteps: # Right before we build, lay down the universal package and localizations - - task: PkgESSetupBuild@12 - displayName: Package ES - Setup Build - inputs: - disableOutputRedirect: true + - template: ./build/pipelines/templates-v2/steps-setup-versioning.yml@self - task: UniversalPackages@0 displayName: Download terminal-internal Universal Package @@ -172,10 +166,7 @@ extends: codeSign: ${{ parameters.codeSign }} signingIdentity: ${{ parameters.signingIdentity }} beforeBuildSteps: - - task: PkgESSetupBuild@12 - displayName: Package ES - Setup Build - inputs: - disableOutputRedirect: true + - template: ./build/pipelines/templates-v2/steps-setup-versioning.yml@self # WPF doesn't need the localizations or the universal package, but if it does... put them here. - stage: Package diff --git a/build/pipelines/templates-v2/steps-ensure-nuget-version.yml b/build/pipelines/templates-v2/steps-ensure-nuget-version.yml index fb5cd75e4c..ea5eda5557 100644 --- a/build/pipelines/templates-v2/steps-ensure-nuget-version.yml +++ b/build/pipelines/templates-v2/steps-ensure-nuget-version.yml @@ -1,5 +1,12 @@ steps: -- task: NuGetToolInstaller@1 - displayName: Use NuGet 6.6.1 - inputs: - versionSpec: 6.6.1 +- ${{ if eq(variables['System.CollectionId'], 'cb55739e-4afe-46a3-970f-1b49d8ee7564') }}: + - pwsh: |- + Write-Host "Assuming NuGet is already installed..." + & nuget.exe help + displayName: Assume NuGet is fine + +- ${{ else }}: + - task: NuGetToolInstaller@1 + displayName: Use NuGet 6.6.1 + inputs: + versionSpec: 6.6.1 diff --git a/build/pipelines/templates-v2/steps-esrp-signing.yml b/build/pipelines/templates-v2/steps-esrp-signing.yml index 9a8e6dbd9a..ef5a8d776b 100644 --- a/build/pipelines/templates-v2/steps-esrp-signing.yml +++ b/build/pipelines/templates-v2/steps-esrp-signing.yml @@ -19,4 +19,6 @@ steps: AuthAKVName: ${{ parameters.signingIdentity.akvName }} AuthCertName: ${{ parameters.signingIdentity.authCertName }} AuthSignCertName: ${{ parameters.signingIdentity.signCertName }} + UseMSIAuthentication: ${{ coalesce(parameters.signingIdentity.useManagedIdentity, 'false') }} + EsrpClientId: ${{ parameters.signingIdentity.clientId }} ${{ insert }}: ${{ parameters.inputs }} diff --git a/build/pipelines/templates-v2/steps-install-vcpkg.yml b/build/pipelines/templates-v2/steps-install-vcpkg.yml new file mode 100644 index 0000000000..ec7c3f3c9a --- /dev/null +++ b/build/pipelines/templates-v2/steps-install-vcpkg.yml @@ -0,0 +1,16 @@ +steps: + - pwsh: |- + $VsInstallRoot = & 'C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe' -requires Microsoft.VisualStudio.Component.Vcpkg -property installationPath + If ([String]::IsNullOrEmpty($VsInstallRoot)) { + Remove-Item -Recurse -Force dep/vcpkg -ErrorAction:Ignore + git clone https://github.com/microsoft/vcpkg dep/vcpkg + cd dep/vcpkg + & ./bootstrap-vcpkg.bat + $VcpkgRoot = $PWD + Write-Host "Using vcpkg from local checkout ($VcpkgRoot)" + } Else { + $VcpkgRoot = Join-Path $VsInstallRoot "VC\vcpkg" + Write-Host "Using vcpkg from Visual Studio installation ($VcpkgRoot)" + } + echo "##vso[task.setvariable variable=VCPKG_ROOT]$VcpkgRoot" + displayName: Detect VS vcpkg or bootstrap locally diff --git a/build/pipelines/templates-v2/steps-setup-versioning.yml b/build/pipelines/templates-v2/steps-setup-versioning.yml new file mode 100644 index 0000000000..8bca260c7c --- /dev/null +++ b/build/pipelines/templates-v2/steps-setup-versioning.yml @@ -0,0 +1,6 @@ +steps: + - pwsh: |- + nuget install Microsoft.Windows.Terminal.Versioning -OutputDirectory _versioning + $VersionRoot = (Get-Item _versioning\Microsoft.Windows.*).FullName + & "$VersionRoot\build\Setup.ps1" -ProjectDirectory "$(Build.SourcesDirectory)" -Verbose + displayName: Set up versioning via M.W.T.V diff --git a/build/rules/Microsoft.WindowsPackageManager.ComInterop.Additional.targets b/build/rules/Microsoft.WindowsPackageManager.ComInterop.Additional.targets new file mode 100644 index 0000000000..be2a691bb2 --- /dev/null +++ b/build/rules/Microsoft.WindowsPackageManager.ComInterop.Additional.targets @@ -0,0 +1,22 @@ + + + + + x86 + $(Platform) + + + + true + + + + + + CustomOutputGroupForPackaging + $(ProjectName) + Microsoft.Management.Deployment.winmd + + + + \ No newline at end of file diff --git a/build/scripts/New-UnpackagedTerminalDistribution.ps1 b/build/scripts/New-UnpackagedTerminalDistribution.ps1 index 9605f13256..9f8d295be8 100644 --- a/build/scripts/New-UnpackagedTerminalDistribution.ps1 +++ b/build/scripts/New-UnpackagedTerminalDistribution.ps1 @@ -34,7 +34,7 @@ Param( ) $filesToRemove = @("*.xml", "*.winmd", "Appx*", "Images/*Tile*", "Images/*Logo*") # Remove from Terminal -$filesToKeep = @("Microsoft.Terminal.Remoting.winmd") # ... except for these +$filesToKeep = @() # ... except for these $filesToCopyFromXaml = @("Microsoft.UI.Xaml.dll", "Microsoft.UI.Xaml") # We don't need the .winmd $ErrorActionPreference = 'Stop' diff --git a/build/scripts/Set-LatestVCToolsVersion.ps1 b/build/scripts/Set-LatestVCToolsVersion.ps1 index 54a43b3a01..4ebf3a3eec 100644 --- a/build/scripts/Set-LatestVCToolsVersion.ps1 +++ b/build/scripts/Set-LatestVCToolsVersion.ps1 @@ -1,8 +1,28 @@ $VSInstances = ([xml](& 'C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe' -latest -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 -include packages -format xml)) $VSPackages = $VSInstances.instances.instance.packages.package -$LatestVCPackage = ($VSInstances.instances.instance.packages.package | ? { $_.id -eq "Microsoft.VisualCpp.CRT.Source" }) +$LatestVCPackage = ($VSPackages | ? { $_.id -eq "Microsoft.VisualCpp.Tools.Core" }) $LatestVCToolsVersion = $LatestVCPackage.version; +$VSRoot = (& 'C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe' -latest -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 -property 'resolvedInstallationPath') +$VCToolsRoot = Join-Path $VSRoot "VC\Tools\MSVC" + +# We have observed a few instances where the VC tools package version actually +# differs from the version on the files themselves. We might as well check +# whether the version we just found _actually exists_ before we use it. +# We'll use whichever highest version exists. +$PackageVCToolPath = Join-Path $VCToolsRoot $LatestVCToolsVersion +If ($Null -Eq (Get-Item $PackageVCToolPath -ErrorAction:Ignore)) { + $VCToolsVersions = Get-ChildItem $VCToolsRoot | ForEach-Object { + [Version]$_.Name + } | Sort -Descending + $LatestActualVCToolsVersion = $VCToolsVersions | Select -First 1 + + If ([Version]$LatestVCToolsVersion -Ne $LatestActualVCToolsVersion) { + Write-Output "VC Tools Mismatch: Directory = $LatestActualVCToolsVersion, Package = $LatestVCToolsVersion" + $LatestVCToolsVersion = $LatestActualVCToolsVersion.ToString(3) + } +} + Write-Output "Latest VCToolsVersion: $LatestVCToolsVersion" Write-Output "Updating VCToolsVersion environment variable for job" Write-Output "##vso[task.setvariable variable=VCToolsVersion]$LatestVCToolsVersion" diff --git a/build/scripts/Test-WindowsTerminalPackage.ps1 b/build/scripts/Test-WindowsTerminalPackage.ps1 index b405d98c21..b492eca05f 100644 --- a/build/scripts/Test-WindowsTerminalPackage.ps1 +++ b/build/scripts/Test-WindowsTerminalPackage.ps1 @@ -58,7 +58,7 @@ Try { ### Check the activatable class entries for a few DLLs we need. $inProcServers = $Manifest.Package.Extensions.Extension.InProcessServer.Path - $RequiredInProcServers = ("TerminalApp.dll", "Microsoft.Terminal.Control.dll", "Microsoft.Terminal.Remoting.dll", "Microsoft.Terminal.Settings.Editor.dll", "Microsoft.Terminal.Settings.Model.dll", "TerminalConnection.dll") + $RequiredInProcServers = ("TerminalApp.dll", "Microsoft.Terminal.Control.dll", "Microsoft.Terminal.Settings.Editor.dll", "Microsoft.Terminal.Settings.Model.dll", "TerminalConnection.dll") Write-Verbose "InProc Servers: $inProcServers" diff --git a/consolegit2gitfilters.json b/consolegit2gitfilters.json index 3dbcfdc9a2..1d570f2497 100644 --- a/consolegit2gitfilters.json +++ b/consolegit2gitfilters.json @@ -24,8 +24,6 @@ "/doc/specs/", "/doc/cascadia/", "/doc/user-docs/", - "/src/tools/MonarchPeasantSample/", - "/src/tools/MonarchPeasantPackage/", "/src/tools/ansi-color/", "/src/tools/ColorTool/", "/scratch/", diff --git a/custom.props b/custom.props index 3227f85d7e..8e358b3e0b 100644 --- a/custom.props +++ b/custom.props @@ -3,9 +3,9 @@ true - 2024 + 2025 1 - 22 + 24 Windows Terminal diff --git a/dep/CLI11/CLI11.hpp b/dep/CLI11/CLI11.hpp deleted file mode 100644 index 632c94c839..0000000000 --- a/dep/CLI11/CLI11.hpp +++ /dev/null @@ -1,10968 +0,0 @@ -// CLI11: Version 2.4.1 -// Originally designed by Henry Schreiner -// https://github.com/CLIUtils/CLI11 -// -// This is a standalone header file generated by MakeSingleHeader.py in CLI11/scripts -// from: v2.4.1 -// -// CLI11 2.4.1 Copyright (c) 2017-2024 University of Cincinnati, developed by Henry -// Schreiner under NSF AWARD 1414736. All rights reserved. -// -// Redistribution and use in source and binary forms of CLI11, with or without -// modification, are permitted provided that the following conditions are met: -// -// 1. Redistributions of source code must retain the above copyright notice, this -// list of conditions and the following disclaimer. -// 2. Redistributions in binary form must reproduce the above copyright notice, -// this list of conditions and the following disclaimer in the documentation -// and/or other materials provided with the distribution. -// 3. Neither the name of the copyright holder nor the names of its contributors -// may be used to endorse or promote products derived from this software without -// specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR -// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#pragma once - -// Standard combined includes: -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -#define CLI11_VERSION_MAJOR 2 -#define CLI11_VERSION_MINOR 4 -#define CLI11_VERSION_PATCH 1 -#define CLI11_VERSION "2.4.1" - - - - -// The following version macro is very similar to the one in pybind11 -#if !(defined(_MSC_VER) && __cplusplus == 199711L) && !defined(__INTEL_COMPILER) -#if __cplusplus >= 201402L -#define CLI11_CPP14 -#if __cplusplus >= 201703L -#define CLI11_CPP17 -#if __cplusplus > 201703L -#define CLI11_CPP20 -#endif -#endif -#endif -#elif defined(_MSC_VER) && __cplusplus == 199711L -// MSVC sets _MSVC_LANG rather than __cplusplus (supposedly until the standard is fully implemented) -// Unless you use the /Zc:__cplusplus flag on Visual Studio 2017 15.7 Preview 3 or newer -#if _MSVC_LANG >= 201402L -#define CLI11_CPP14 -#if _MSVC_LANG > 201402L && _MSC_VER >= 1910 -#define CLI11_CPP17 -#if _MSVC_LANG > 201703L && _MSC_VER >= 1910 -#define CLI11_CPP20 -#endif -#endif -#endif -#endif - -#if defined(CLI11_CPP14) -#define CLI11_DEPRECATED(reason) [[deprecated(reason)]] -#elif defined(_MSC_VER) -#define CLI11_DEPRECATED(reason) __declspec(deprecated(reason)) -#else -#define CLI11_DEPRECATED(reason) __attribute__((deprecated(reason))) -#endif - -// GCC < 10 doesn't ignore this in unevaluated contexts -#if !defined(CLI11_CPP17) || \ - (defined(__GNUC__) && !defined(__llvm__) && !defined(__INTEL_COMPILER) && __GNUC__ < 10 && __GNUC__ > 4) -#define CLI11_NODISCARD -#else -#define CLI11_NODISCARD [[nodiscard]] -#endif - -/** detection of rtti */ -#define CLI11_USE_STATIC_RTTI 0 // CLANG-BAD-HAX - -#ifndef CLI11_USE_STATIC_RTTI -#if(defined(_HAS_STATIC_RTTI) && _HAS_STATIC_RTTI) -#define CLI11_USE_STATIC_RTTI 1 -#elif defined(__cpp_rtti) -#if(defined(_CPPRTTI) && _CPPRTTI == 0) -#define CLI11_USE_STATIC_RTTI 1 -#else -#define CLI11_USE_STATIC_RTTI 0 -#endif -#elif(defined(__GCC_RTTI) && __GXX_RTTI) -#define CLI11_USE_STATIC_RTTI 0 -#else -#define CLI11_USE_STATIC_RTTI 1 -#endif -#endif - -/** availability */ -#if defined CLI11_CPP17 && defined __has_include && !defined CLI11_HAS_FILESYSTEM -#if __has_include() -// Filesystem cannot be used if targeting macOS < 10.15 -#if defined __MAC_OS_X_VERSION_MIN_REQUIRED && __MAC_OS_X_VERSION_MIN_REQUIRED < 101500 -#define CLI11_HAS_FILESYSTEM 0 -#elif defined(__wasi__) -// As of wasi-sdk-14, filesystem is not implemented -#define CLI11_HAS_FILESYSTEM 0 -#else -#include -#if defined __cpp_lib_filesystem && __cpp_lib_filesystem >= 201703 -#if defined _GLIBCXX_RELEASE && _GLIBCXX_RELEASE >= 9 -#define CLI11_HAS_FILESYSTEM 1 -#elif defined(__GLIBCXX__) -// if we are using gcc and Version <9 default to no filesystem -#define CLI11_HAS_FILESYSTEM 0 -#else -#define CLI11_HAS_FILESYSTEM 1 -#endif -#else -#define CLI11_HAS_FILESYSTEM 0 -#endif -#endif -#endif -#endif - -/** availability */ -#if defined(__GNUC__) && !defined(__llvm__) && !defined(__INTEL_COMPILER) && __GNUC__ < 5 -#define CLI11_HAS_CODECVT 0 -#else -#define CLI11_HAS_CODECVT 1 -#include -#endif - -/** disable deprecations */ -#if defined(__GNUC__) // GCC or clang -#define CLI11_DIAGNOSTIC_PUSH _Pragma("GCC diagnostic push") -#define CLI11_DIAGNOSTIC_POP _Pragma("GCC diagnostic pop") - -#define CLI11_DIAGNOSTIC_IGNORE_DEPRECATED _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"") - -#elif defined(_MSC_VER) -#define CLI11_DIAGNOSTIC_PUSH __pragma(warning(push)) -#define CLI11_DIAGNOSTIC_POP __pragma(warning(pop)) - -#define CLI11_DIAGNOSTIC_IGNORE_DEPRECATED __pragma(warning(disable : 4996)) - -#else -#define CLI11_DIAGNOSTIC_PUSH -#define CLI11_DIAGNOSTIC_POP - -#define CLI11_DIAGNOSTIC_IGNORE_DEPRECATED - -#endif - -/** Inline macro **/ -#ifdef CLI11_COMPILE -#define CLI11_INLINE -#else -#define CLI11_INLINE inline -#endif - - - -#if defined CLI11_HAS_FILESYSTEM && CLI11_HAS_FILESYSTEM > 0 -#include // NOLINT(build/include) -#else -#include -#include -#endif - - - - -#ifdef CLI11_CPP17 -#include -#endif // CLI11_CPP17 - -#if defined CLI11_HAS_FILESYSTEM && CLI11_HAS_FILESYSTEM > 0 -#include -#include // NOLINT(build/include) -#endif // CLI11_HAS_FILESYSTEM - - - -#if defined(_WIN32) -#if !(defined(_AMD64_) || defined(_X86_) || defined(_ARM_)) -#if defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64) || defined(_M_X64) || \ - defined(_M_AMD64) -#define _AMD64_ -#elif defined(i386) || defined(__i386) || defined(__i386__) || defined(__i386__) || defined(_M_IX86) -#define _X86_ -#elif defined(__arm__) || defined(_M_ARM) || defined(_M_ARMT) -#define _ARM_ -#elif defined(__aarch64__) || defined(_M_ARM64) -#define _ARM64_ -#elif defined(_M_ARM64EC) -#define _ARM64EC_ -#endif -#endif - -// first -#ifndef NOMINMAX -// if NOMINMAX is already defined we don't want to mess with that either way -#define NOMINMAX -#include -#undef NOMINMAX -#else -#include -#endif - -// second -#include -// third -#include -#include -#endif - - -namespace CLI { - - -/// Convert a wide string to a narrow string. -CLI11_INLINE std::string narrow(const std::wstring &str); -CLI11_INLINE std::string narrow(const wchar_t *str); -CLI11_INLINE std::string narrow(const wchar_t *str, std::size_t size); - -/// Convert a narrow string to a wide string. -CLI11_INLINE std::wstring widen(const std::string &str); -CLI11_INLINE std::wstring widen(const char *str); -CLI11_INLINE std::wstring widen(const char *str, std::size_t size); - -#ifdef CLI11_CPP17 -CLI11_INLINE std::string narrow(std::wstring_view str); -CLI11_INLINE std::wstring widen(std::string_view str); -#endif // CLI11_CPP17 - -#if defined CLI11_HAS_FILESYSTEM && CLI11_HAS_FILESYSTEM > 0 -/// Convert a char-string to a native path correctly. -CLI11_INLINE std::filesystem::path to_path(std::string_view str); -#endif // CLI11_HAS_FILESYSTEM - - - - -namespace detail { - -#if !CLI11_HAS_CODECVT -/// Attempt to set one of the acceptable unicode locales for conversion -CLI11_INLINE void set_unicode_locale() { - static const std::array unicode_locales{{"C.UTF-8", "en_US.UTF-8", ".UTF-8"}}; - - for(const auto &locale_name : unicode_locales) { - if(std::setlocale(LC_ALL, locale_name) != nullptr) { - return; - } - } - throw std::runtime_error("CLI::narrow: could not set locale to C.UTF-8"); -} - -template struct scope_guard_t { - F closure; - - explicit scope_guard_t(F closure_) : closure(closure_) {} - ~scope_guard_t() { closure(); } -}; - -template CLI11_NODISCARD CLI11_INLINE scope_guard_t scope_guard(F &&closure) { - return scope_guard_t{std::forward(closure)}; -} - -#endif // !CLI11_HAS_CODECVT - -CLI11_DIAGNOSTIC_PUSH -CLI11_DIAGNOSTIC_IGNORE_DEPRECATED - -CLI11_INLINE std::string narrow_impl(const wchar_t *str, std::size_t str_size) { -#if CLI11_HAS_CODECVT -#ifdef _WIN32 - return std::wstring_convert>().to_bytes(str, str + str_size); - -#else - return std::wstring_convert>().to_bytes(str, str + str_size); - -#endif // _WIN32 -#else // CLI11_HAS_CODECVT - (void)str_size; - std::mbstate_t state = std::mbstate_t(); - const wchar_t *it = str; - - std::string old_locale = std::setlocale(LC_ALL, nullptr); - auto sg = scope_guard([&] { std::setlocale(LC_ALL, old_locale.c_str()); }); - set_unicode_locale(); - - std::size_t new_size = std::wcsrtombs(nullptr, &it, 0, &state); - if(new_size == static_cast(-1)) { - throw std::runtime_error("CLI::narrow: conversion error in std::wcsrtombs at offset " + - std::to_string(it - str)); - } - std::string result(new_size, '\0'); - std::wcsrtombs(const_cast(result.data()), &str, new_size, &state); - - return result; - -#endif // CLI11_HAS_CODECVT -} - -CLI11_INLINE std::wstring widen_impl(const char *str, std::size_t str_size) { -#if CLI11_HAS_CODECVT -#ifdef _WIN32 - return std::wstring_convert>().from_bytes(str, str + str_size); - -#else - return std::wstring_convert>().from_bytes(str, str + str_size); - -#endif // _WIN32 -#else // CLI11_HAS_CODECVT - (void)str_size; - std::mbstate_t state = std::mbstate_t(); - const char *it = str; - - std::string old_locale = std::setlocale(LC_ALL, nullptr); - auto sg = scope_guard([&] { std::setlocale(LC_ALL, old_locale.c_str()); }); - set_unicode_locale(); - - std::size_t new_size = std::mbsrtowcs(nullptr, &it, 0, &state); - if(new_size == static_cast(-1)) { - throw std::runtime_error("CLI::widen: conversion error in std::mbsrtowcs at offset " + - std::to_string(it - str)); - } - std::wstring result(new_size, L'\0'); - std::mbsrtowcs(const_cast(result.data()), &str, new_size, &state); - - return result; - -#endif // CLI11_HAS_CODECVT -} - -CLI11_DIAGNOSTIC_POP - -} // namespace detail - -CLI11_INLINE std::string narrow(const wchar_t *str, std::size_t str_size) { return detail::narrow_impl(str, str_size); } -CLI11_INLINE std::string narrow(const std::wstring &str) { return detail::narrow_impl(str.data(), str.size()); } -// Flawfinder: ignore -CLI11_INLINE std::string narrow(const wchar_t *str) { return detail::narrow_impl(str, std::wcslen(str)); } - -CLI11_INLINE std::wstring widen(const char *str, std::size_t str_size) { return detail::widen_impl(str, str_size); } -CLI11_INLINE std::wstring widen(const std::string &str) { return detail::widen_impl(str.data(), str.size()); } -// Flawfinder: ignore -CLI11_INLINE std::wstring widen(const char *str) { return detail::widen_impl(str, std::strlen(str)); } - -#ifdef CLI11_CPP17 -CLI11_INLINE std::string narrow(std::wstring_view str) { return detail::narrow_impl(str.data(), str.size()); } -CLI11_INLINE std::wstring widen(std::string_view str) { return detail::widen_impl(str.data(), str.size()); } -#endif // CLI11_CPP17 - -#if defined CLI11_HAS_FILESYSTEM && CLI11_HAS_FILESYSTEM > 0 -CLI11_INLINE std::filesystem::path to_path(std::string_view str) { - return std::filesystem::path{ -#ifdef _WIN32 - widen(str) -#else - str -#endif // _WIN32 - }; -} -#endif // CLI11_HAS_FILESYSTEM - - - - -namespace detail { -#ifdef _WIN32 -/// Decode and return UTF-8 argv from GetCommandLineW. -CLI11_INLINE std::vector compute_win32_argv(); -#endif -} // namespace detail - - - -namespace detail { - -#ifdef _WIN32 -CLI11_INLINE std::vector compute_win32_argv() { - std::vector result; - int argc = 0; - - auto deleter = [](wchar_t **ptr) { LocalFree(ptr); }; - // NOLINTBEGIN(*-avoid-c-arrays) - auto wargv = std::unique_ptr(CommandLineToArgvW(GetCommandLineW(), &argc), deleter); - // NOLINTEND(*-avoid-c-arrays) - - if(wargv == nullptr) { - throw std::runtime_error("CommandLineToArgvW failed with code " + std::to_string(GetLastError())); - } - - result.reserve(static_cast(argc)); - for(size_t i = 0; i < static_cast(argc); ++i) { - result.push_back(narrow(wargv[i])); - } - - return result; -} -#endif - -} // namespace detail - - - - -/// Include the items in this namespace to get free conversion of enums to/from streams. -/// (This is available inside CLI as well, so CLI11 will use this without a using statement). -namespace enums { - -/// output streaming for enumerations -template ::value>::type> -std::ostream &operator<<(std::ostream &in, const T &item) { - // make sure this is out of the detail namespace otherwise it won't be found when needed - return in << static_cast::type>(item); -} - -} // namespace enums - -/// Export to CLI namespace -using enums::operator<<; - -namespace detail { -/// a constant defining an expected max vector size defined to be a big number that could be multiplied by 4 and not -/// produce overflow for some expected uses -constexpr int expected_max_vector_size{1 << 29}; -// Based on http://stackoverflow.com/questions/236129/split-a-string-in-c -/// Split a string by a delim -CLI11_INLINE std::vector split(const std::string &s, char delim); - -/// Simple function to join a string -template std::string join(const T &v, std::string delim = ",") { - std::ostringstream s; - auto beg = std::begin(v); - auto end = std::end(v); - if(beg != end) - s << *beg++; - while(beg != end) { - s << delim << *beg++; - } - return s.str(); -} - -/// Simple function to join a string from processed elements -template ::value>::type> -std::string join(const T &v, Callable func, std::string delim = ",") { - std::ostringstream s; - auto beg = std::begin(v); - auto end = std::end(v); - auto loc = s.tellp(); - while(beg != end) { - auto nloc = s.tellp(); - if(nloc > loc) { - s << delim; - loc = nloc; - } - s << func(*beg++); - } - return s.str(); -} - -/// Join a string in reverse order -template std::string rjoin(const T &v, std::string delim = ",") { - std::ostringstream s; - for(std::size_t start = 0; start < v.size(); start++) { - if(start > 0) - s << delim; - s << v[v.size() - start - 1]; - } - return s.str(); -} - -// Based roughly on http://stackoverflow.com/questions/25829143/c-trim-whitespace-from-a-string - -/// Trim whitespace from left of string -CLI11_INLINE std::string <rim(std::string &str); - -/// Trim anything from left of string -CLI11_INLINE std::string <rim(std::string &str, const std::string &filter); - -/// Trim whitespace from right of string -CLI11_INLINE std::string &rtrim(std::string &str); - -/// Trim anything from right of string -CLI11_INLINE std::string &rtrim(std::string &str, const std::string &filter); - -/// Trim whitespace from string -inline std::string &trim(std::string &str) { return ltrim(rtrim(str)); } - -/// Trim anything from string -inline std::string &trim(std::string &str, const std::string filter) { return ltrim(rtrim(str, filter), filter); } - -/// Make a copy of the string and then trim it -inline std::string trim_copy(const std::string &str) { - std::string s = str; - return trim(s); -} - -/// remove quotes at the front and back of a string either '"' or '\'' -CLI11_INLINE std::string &remove_quotes(std::string &str); - -/// remove quotes from all elements of a string vector and process escaped components -CLI11_INLINE void remove_quotes(std::vector &args); - -/// Add a leader to the beginning of all new lines (nothing is added -/// at the start of the first line). `"; "` would be for ini files -/// -/// Can't use Regex, or this would be a subs. -CLI11_INLINE std::string fix_newlines(const std::string &leader, std::string input); - -/// Make a copy of the string and then trim it, any filter string can be used (any char in string is filtered) -inline std::string trim_copy(const std::string &str, const std::string &filter) { - std::string s = str; - return trim(s, filter); -} -/// Print a two part "help" string -CLI11_INLINE std::ostream & -format_help(std::ostream &out, std::string name, const std::string &description, std::size_t wid); - -/// Print subcommand aliases -CLI11_INLINE std::ostream &format_aliases(std::ostream &out, const std::vector &aliases, std::size_t wid); - -/// Verify the first character of an option -/// - is a trigger character, ! has special meaning and new lines would just be annoying to deal with -template bool valid_first_char(T c) { - return ((c != '-') && (static_cast(c) > 33)); // space and '!' not allowed -} - -/// Verify following characters of an option -template bool valid_later_char(T c) { - // = and : are value separators, { has special meaning for option defaults, - // and control codes other than tab would just be annoying to deal with in many places allowing space here has too - // much potential for inadvertent entry errors and bugs - return ((c != '=') && (c != ':') && (c != '{') && ((static_cast(c) > 32) || c == '\t')); -} - -/// Verify an option/subcommand name -CLI11_INLINE bool valid_name_string(const std::string &str); - -/// Verify an app name -inline bool valid_alias_name_string(const std::string &str) { - static const std::string badChars(std::string("\n") + '\0'); - return (str.find_first_of(badChars) == std::string::npos); -} - -/// check if a string is a container segment separator (empty or "%%") -inline bool is_separator(const std::string &str) { - static const std::string sep("%%"); - return (str.empty() || str == sep); -} - -/// Verify that str consists of letters only -inline bool isalpha(const std::string &str) { - return std::all_of(str.begin(), str.end(), [](char c) { return std::isalpha(c, std::locale()); }); -} - -/// Return a lower case version of a string -inline std::string to_lower(std::string str) { - std::transform(std::begin(str), std::end(str), std::begin(str), [](const std::string::value_type &x) { - return std::tolower(x, std::locale()); - }); - return str; -} - -/// remove underscores from a string -inline std::string remove_underscore(std::string str) { - str.erase(std::remove(std::begin(str), std::end(str), '_'), std::end(str)); - return str; -} - -/// Find and replace a substring with another substring -CLI11_INLINE std::string find_and_replace(std::string str, std::string from, std::string to); - -/// check if the flag definitions has possible false flags -inline bool has_default_flag_values(const std::string &flags) { - return (flags.find_first_of("{!") != std::string::npos); -} - -CLI11_INLINE void remove_default_flag_values(std::string &flags); - -/// Check if a string is a member of a list of strings and optionally ignore case or ignore underscores -CLI11_INLINE std::ptrdiff_t find_member(std::string name, - const std::vector names, - bool ignore_case = false, - bool ignore_underscore = false); - -/// Find a trigger string and call a modify callable function that takes the current string and starting position of the -/// trigger and returns the position in the string to search for the next trigger string -template inline std::string find_and_modify(std::string str, std::string trigger, Callable modify) { - std::size_t start_pos = 0; - while((start_pos = str.find(trigger, start_pos)) != std::string::npos) { - start_pos = modify(str, start_pos); - } - return str; -} - -/// close a sequence of characters indicated by a closure character. Brackets allows sub sequences -/// recognized bracket sequences include "'`[(<{ other closure characters are assumed to be literal strings -CLI11_INLINE std::size_t close_sequence(const std::string &str, std::size_t start, char closure_char); - -/// Split a string '"one two" "three"' into 'one two', 'three' -/// Quote characters can be ` ' or " or bracket characters [{(< with matching to the matching bracket -CLI11_INLINE std::vector split_up(std::string str, char delimiter = '\0'); - -/// get the value of an environmental variable or empty string if empty -CLI11_INLINE std::string get_environment_value(const std::string &env_name); - -/// This function detects an equal or colon followed by an escaped quote after an argument -/// then modifies the string to replace the equality with a space. This is needed -/// to allow the split up function to work properly and is intended to be used with the find_and_modify function -/// the return value is the offset+1 which is required by the find_and_modify function. -CLI11_INLINE std::size_t escape_detect(std::string &str, std::size_t offset); - -/// @brief detect if a string has escapable characters -/// @param str the string to do the detection on -/// @return true if the string has escapable characters -CLI11_INLINE bool has_escapable_character(const std::string &str); - -/// @brief escape all escapable characters -/// @param str the string to escape -/// @return a string with the escapble characters escaped with '\' -CLI11_INLINE std::string add_escaped_characters(const std::string &str); - -/// @brief replace the escaped characters with their equivalent -CLI11_INLINE std::string remove_escaped_characters(const std::string &str); - -/// generate a string with all non printable characters escaped to hex codes -CLI11_INLINE std::string binary_escape_string(const std::string &string_to_escape); - -CLI11_INLINE bool is_binary_escaped_string(const std::string &escaped_string); - -/// extract an escaped binary_string -CLI11_INLINE std::string extract_binary_string(const std::string &escaped_string); - -/// process a quoted string, remove the quotes and if appropriate handle escaped characters -CLI11_INLINE bool process_quoted_string(std::string &str, char string_char = '\"', char literal_char = '\''); - -} // namespace detail - - - - -namespace detail { -CLI11_INLINE std::vector split(const std::string &s, char delim) { - std::vector elems; - // Check to see if empty string, give consistent result - if(s.empty()) { - elems.emplace_back(); - } else { - std::stringstream ss; - ss.str(s); - std::string item; - while(std::getline(ss, item, delim)) { - elems.push_back(item); - } - } - return elems; -} - -CLI11_INLINE std::string <rim(std::string &str) { - auto it = std::find_if(str.begin(), str.end(), [](char ch) { return !std::isspace(ch, std::locale()); }); - str.erase(str.begin(), it); - return str; -} - -CLI11_INLINE std::string <rim(std::string &str, const std::string &filter) { - auto it = std::find_if(str.begin(), str.end(), [&filter](char ch) { return filter.find(ch) == std::string::npos; }); - str.erase(str.begin(), it); - return str; -} - -CLI11_INLINE std::string &rtrim(std::string &str) { - auto it = std::find_if(str.rbegin(), str.rend(), [](char ch) { return !std::isspace(ch, std::locale()); }); - str.erase(it.base(), str.end()); - return str; -} - -CLI11_INLINE std::string &rtrim(std::string &str, const std::string &filter) { - auto it = - std::find_if(str.rbegin(), str.rend(), [&filter](char ch) { return filter.find(ch) == std::string::npos; }); - str.erase(it.base(), str.end()); - return str; -} - -CLI11_INLINE std::string &remove_quotes(std::string &str) { - if(str.length() > 1 && (str.front() == '"' || str.front() == '\'' || str.front() == '`')) { - if(str.front() == str.back()) { - str.pop_back(); - str.erase(str.begin(), str.begin() + 1); - } - } - return str; -} - -CLI11_INLINE std::string &remove_outer(std::string &str, char key) { - if(str.length() > 1 && (str.front() == key)) { - if(str.front() == str.back()) { - str.pop_back(); - str.erase(str.begin(), str.begin() + 1); - } - } - return str; -} - -CLI11_INLINE std::string fix_newlines(const std::string &leader, std::string input) { - std::string::size_type n = 0; - while(n != std::string::npos && n < input.size()) { - n = input.find('\n', n); - if(n != std::string::npos) { - input = input.substr(0, n + 1) + leader + input.substr(n + 1); - n += leader.size(); - } - } - return input; -} - -CLI11_INLINE std::ostream & -format_help(std::ostream &out, std::string name, const std::string &description, std::size_t wid) { - name = " " + name; - out << std::setw(static_cast(wid)) << std::left << name; - if(!description.empty()) { - if(name.length() >= wid) - out << "\n" << std::setw(static_cast(wid)) << ""; - for(const char c : description) { - out.put(c); - if(c == '\n') { - out << std::setw(static_cast(wid)) << ""; - } - } - } - out << "\n"; - return out; -} - -CLI11_INLINE std::ostream &format_aliases(std::ostream &out, const std::vector &aliases, std::size_t wid) { - if(!aliases.empty()) { - out << std::setw(static_cast(wid)) << " aliases: "; - bool front = true; - for(const auto &alias : aliases) { - if(!front) { - out << ", "; - } else { - front = false; - } - out << detail::fix_newlines(" ", alias); - } - out << "\n"; - } - return out; -} - -CLI11_INLINE bool valid_name_string(const std::string &str) { - if(str.empty() || !valid_first_char(str[0])) { - return false; - } - auto e = str.end(); - for(auto c = str.begin() + 1; c != e; ++c) - if(!valid_later_char(*c)) - return false; - return true; -} - -CLI11_INLINE std::string find_and_replace(std::string str, std::string from, std::string to) { - - std::size_t start_pos = 0; - - while((start_pos = str.find(from, start_pos)) != std::string::npos) { - str.replace(start_pos, from.length(), to); - start_pos += to.length(); - } - - return str; -} - -CLI11_INLINE void remove_default_flag_values(std::string &flags) { - auto loc = flags.find_first_of('{', 2); - while(loc != std::string::npos) { - auto finish = flags.find_first_of("},", loc + 1); - if((finish != std::string::npos) && (flags[finish] == '}')) { - flags.erase(flags.begin() + static_cast(loc), - flags.begin() + static_cast(finish) + 1); - } - loc = flags.find_first_of('{', loc + 1); - } - flags.erase(std::remove(flags.begin(), flags.end(), '!'), flags.end()); -} - -CLI11_INLINE std::ptrdiff_t -find_member(std::string name, const std::vector names, bool ignore_case, bool ignore_underscore) { - auto it = std::end(names); - if(ignore_case) { - if(ignore_underscore) { - name = detail::to_lower(detail::remove_underscore(name)); - it = std::find_if(std::begin(names), std::end(names), [&name](std::string local_name) { - return detail::to_lower(detail::remove_underscore(local_name)) == name; - }); - } else { - name = detail::to_lower(name); - it = std::find_if(std::begin(names), std::end(names), [&name](std::string local_name) { - return detail::to_lower(local_name) == name; - }); - } - - } else if(ignore_underscore) { - name = detail::remove_underscore(name); - it = std::find_if(std::begin(names), std::end(names), [&name](std::string local_name) { - return detail::remove_underscore(local_name) == name; - }); - } else { - it = std::find(std::begin(names), std::end(names), name); - } - - return (it != std::end(names)) ? (it - std::begin(names)) : (-1); -} - -static const std::string escapedChars("\b\t\n\f\r\"\\"); -static const std::string escapedCharsCode("btnfr\"\\"); -static const std::string bracketChars{"\"'`[(<{"}; -static const std::string matchBracketChars("\"'`])>}"); - -CLI11_INLINE bool has_escapable_character(const std::string &str) { - return (str.find_first_of(escapedChars) != std::string::npos); -} - -CLI11_INLINE std::string add_escaped_characters(const std::string &str) { - std::string out; - out.reserve(str.size() + 4); - for(char s : str) { - auto sloc = escapedChars.find_first_of(s); - if(sloc != std::string::npos) { - out.push_back('\\'); - out.push_back(escapedCharsCode[sloc]); - } else { - out.push_back(s); - } - } - return out; -} - -CLI11_INLINE std::uint32_t hexConvert(char hc) { - int hcode{0}; - if(hc >= '0' && hc <= '9') { - hcode = (hc - '0'); - } else if(hc >= 'A' && hc <= 'F') { - hcode = (hc - 'A' + 10); - } else if(hc >= 'a' && hc <= 'f') { - hcode = (hc - 'a' + 10); - } else { - hcode = -1; - } - return static_cast(hcode); -} - -CLI11_INLINE char make_char(std::uint32_t code) { return static_cast(static_cast(code)); } - -CLI11_INLINE void append_codepoint(std::string &str, std::uint32_t code) { - if(code < 0x80) { // ascii code equivalent - str.push_back(static_cast(code)); - } else if(code < 0x800) { // \u0080 to \u07FF - // 110yyyyx 10xxxxxx; 0x3f == 0b0011'1111 - str.push_back(make_char(0xC0 | code >> 6)); - str.push_back(make_char(0x80 | (code & 0x3F))); - } else if(code < 0x10000) { // U+0800...U+FFFF - if(0xD800 <= code && code <= 0xDFFF) { - throw std::invalid_argument("[0xD800, 0xDFFF] are not valid UTF-8."); - } - // 1110yyyy 10yxxxxx 10xxxxxx - str.push_back(make_char(0xE0 | code >> 12)); - str.push_back(make_char(0x80 | (code >> 6 & 0x3F))); - str.push_back(make_char(0x80 | (code & 0x3F))); - } else if(code < 0x110000) { // U+010000 ... U+10FFFF - // 11110yyy 10yyxxxx 10xxxxxx 10xxxxxx - str.push_back(make_char(0xF0 | code >> 18)); - str.push_back(make_char(0x80 | (code >> 12 & 0x3F))); - str.push_back(make_char(0x80 | (code >> 6 & 0x3F))); - str.push_back(make_char(0x80 | (code & 0x3F))); - } -} - -CLI11_INLINE std::string remove_escaped_characters(const std::string &str) { - - std::string out; - out.reserve(str.size()); - for(auto loc = str.begin(); loc < str.end(); ++loc) { - if(*loc == '\\') { - if(str.end() - loc < 2) { - throw std::invalid_argument("invalid escape sequence " + str); - } - auto ecloc = escapedCharsCode.find_first_of(*(loc + 1)); - if(ecloc != std::string::npos) { - out.push_back(escapedChars[ecloc]); - ++loc; - } else if(*(loc + 1) == 'u') { - // must have 4 hex characters - if(str.end() - loc < 6) { - throw std::invalid_argument("unicode sequence must have 4 hex codes " + str); - } - std::uint32_t code{0}; - std::uint32_t mplier{16 * 16 * 16}; - for(int ii = 2; ii < 6; ++ii) { - std::uint32_t res = hexConvert(*(loc + ii)); - if(res > 0x0F) { - throw std::invalid_argument("unicode sequence must have 4 hex codes " + str); - } - code += res * mplier; - mplier = mplier / 16; - } - append_codepoint(out, code); - loc += 5; - } else if(*(loc + 1) == 'U') { - // must have 8 hex characters - if(str.end() - loc < 10) { - throw std::invalid_argument("unicode sequence must have 8 hex codes " + str); - } - std::uint32_t code{0}; - std::uint32_t mplier{16 * 16 * 16 * 16 * 16 * 16 * 16}; - for(int ii = 2; ii < 10; ++ii) { - std::uint32_t res = hexConvert(*(loc + ii)); - if(res > 0x0F) { - throw std::invalid_argument("unicode sequence must have 8 hex codes " + str); - } - code += res * mplier; - mplier = mplier / 16; - } - append_codepoint(out, code); - loc += 9; - } else if(*(loc + 1) == '0') { - out.push_back('\0'); - ++loc; - } else { - throw std::invalid_argument(std::string("unrecognized escape sequence \\") + *(loc + 1) + " in " + str); - } - } else { - out.push_back(*loc); - } - } - return out; -} - -CLI11_INLINE std::size_t close_string_quote(const std::string &str, std::size_t start, char closure_char) { - std::size_t loc{0}; - for(loc = start + 1; loc < str.size(); ++loc) { - if(str[loc] == closure_char) { - break; - } - if(str[loc] == '\\') { - // skip the next character for escaped sequences - ++loc; - } - } - return loc; -} - -CLI11_INLINE std::size_t close_literal_quote(const std::string &str, std::size_t start, char closure_char) { - auto loc = str.find_first_of(closure_char, start + 1); - return (loc != std::string::npos ? loc : str.size()); -} - -CLI11_INLINE std::size_t close_sequence(const std::string &str, std::size_t start, char closure_char) { - - auto bracket_loc = matchBracketChars.find(closure_char); - switch(bracket_loc) { - case 0: - return close_string_quote(str, start, closure_char); - case 1: - case 2: - case std::string::npos: - return close_literal_quote(str, start, closure_char); - default: - break; - } - - std::string closures(1, closure_char); - auto loc = start + 1; - - while(loc < str.size()) { - if(str[loc] == closures.back()) { - closures.pop_back(); - if(closures.empty()) { - return loc; - } - } - bracket_loc = bracketChars.find(str[loc]); - if(bracket_loc != std::string::npos) { - switch(bracket_loc) { - case 0: - loc = close_string_quote(str, loc, str[loc]); - break; - case 1: - case 2: - loc = close_literal_quote(str, loc, str[loc]); - break; - default: - closures.push_back(matchBracketChars[bracket_loc]); - break; - } - } - ++loc; - } - if(loc > str.size()) { - loc = str.size(); - } - return loc; -} - -CLI11_INLINE std::vector split_up(std::string str, char delimiter) { - - auto find_ws = [delimiter](char ch) { - return (delimiter == '\0') ? std::isspace(ch, std::locale()) : (ch == delimiter); - }; - trim(str); - - std::vector output; - while(!str.empty()) { - if(bracketChars.find_first_of(str[0]) != std::string::npos) { - auto bracketLoc = bracketChars.find_first_of(str[0]); - auto end = close_sequence(str, 0, matchBracketChars[bracketLoc]); - if(end >= str.size()) { - output.push_back(std::move(str)); - str.clear(); - } else { - output.push_back(str.substr(0, end + 1)); - if(end + 2 < str.size()) { - str = str.substr(end + 2); - } else { - str.clear(); - } - } - - } else { - auto it = std::find_if(std::begin(str), std::end(str), find_ws); - if(it != std::end(str)) { - std::string value = std::string(str.begin(), it); - output.push_back(value); - str = std::string(it + 1, str.end()); - } else { - output.push_back(str); - str.clear(); - } - } - trim(str); - } - return output; -} - -CLI11_INLINE std::size_t escape_detect(std::string &str, std::size_t offset) { - auto next = str[offset + 1]; - if((next == '\"') || (next == '\'') || (next == '`')) { - auto astart = str.find_last_of("-/ \"\'`", offset - 1); - if(astart != std::string::npos) { - if(str[astart] == ((str[offset] == '=') ? '-' : '/')) - str[offset] = ' '; // interpret this as a space so the split_up works properly - } - } - return offset + 1; -} - -CLI11_INLINE std::string binary_escape_string(const std::string &string_to_escape) { - // s is our escaped output string - std::string escaped_string{}; - // loop through all characters - for(char c : string_to_escape) { - // check if a given character is printable - // the cast is necessary to avoid undefined behaviour - if(isprint(static_cast(c)) == 0) { - std::stringstream stream; - // if the character is not printable - // we'll convert it to a hex string using a stringstream - // note that since char is signed we have to cast it to unsigned first - stream << std::hex << static_cast(static_cast(c)); - std::string code = stream.str(); - escaped_string += std::string("\\x") + (code.size() < 2 ? "0" : "") + code; - - } else { - escaped_string.push_back(c); - } - } - if(escaped_string != string_to_escape) { - auto sqLoc = escaped_string.find('\''); - while(sqLoc != std::string::npos) { - escaped_string.replace(sqLoc, sqLoc + 1, "\\x27"); - sqLoc = escaped_string.find('\''); - } - escaped_string.insert(0, "'B\"("); - escaped_string.push_back(')'); - escaped_string.push_back('"'); - escaped_string.push_back('\''); - } - return escaped_string; -} - -CLI11_INLINE bool is_binary_escaped_string(const std::string &escaped_string) { - size_t ssize = escaped_string.size(); - if(escaped_string.compare(0, 3, "B\"(") == 0 && escaped_string.compare(ssize - 2, 2, ")\"") == 0) { - return true; - } - return (escaped_string.compare(0, 4, "'B\"(") == 0 && escaped_string.compare(ssize - 3, 3, ")\"'") == 0); -} - -CLI11_INLINE std::string extract_binary_string(const std::string &escaped_string) { - std::size_t start{0}; - std::size_t tail{0}; - size_t ssize = escaped_string.size(); - if(escaped_string.compare(0, 3, "B\"(") == 0 && escaped_string.compare(ssize - 2, 2, ")\"") == 0) { - start = 3; - tail = 2; - } else if(escaped_string.compare(0, 4, "'B\"(") == 0 && escaped_string.compare(ssize - 3, 3, ")\"'") == 0) { - start = 4; - tail = 3; - } - - if(start == 0) { - return escaped_string; - } - std::string outstring; - - outstring.reserve(ssize - start - tail); - std::size_t loc = start; - while(loc < ssize - tail) { - // ssize-2 to skip )" at the end - if(escaped_string[loc] == '\\' && (escaped_string[loc + 1] == 'x' || escaped_string[loc + 1] == 'X')) { - auto c1 = escaped_string[loc + 2]; - auto c2 = escaped_string[loc + 3]; - - std::uint32_t res1 = hexConvert(c1); - std::uint32_t res2 = hexConvert(c2); - if(res1 <= 0x0F && res2 <= 0x0F) { - loc += 4; - outstring.push_back(static_cast(res1 * 16 + res2)); - continue; - } - } - outstring.push_back(escaped_string[loc]); - ++loc; - } - return outstring; -} - -CLI11_INLINE void remove_quotes(std::vector &args) { - for(auto &arg : args) { - if(arg.front() == '\"' && arg.back() == '\"') { - remove_quotes(arg); - // only remove escaped for string arguments not literal strings - arg = remove_escaped_characters(arg); - } else { - remove_quotes(arg); - } - } -} - -CLI11_INLINE bool process_quoted_string(std::string &str, char string_char, char literal_char) { - if(str.size() <= 1) { - return false; - } - if(detail::is_binary_escaped_string(str)) { - str = detail::extract_binary_string(str); - return true; - } - if(str.front() == string_char && str.back() == string_char) { - detail::remove_outer(str, string_char); - if(str.find_first_of('\\') != std::string::npos) { - str = detail::remove_escaped_characters(str); - } - return true; - } - if((str.front() == literal_char || str.front() == '`') && str.back() == str.front()) { - detail::remove_outer(str, str.front()); - return true; - } - return false; -} - -std::string get_environment_value(const std::string &env_name) { - char *buffer = nullptr; - std::string ename_string; - -#ifdef _MSC_VER - // Windows version - std::size_t sz = 0; - if(_dupenv_s(&buffer, &sz, env_name.c_str()) == 0 && buffer != nullptr) { - ename_string = std::string(buffer); - free(buffer); - } -#else - // This also works on Windows, but gives a warning - buffer = std::getenv(env_name.c_str()); - if(buffer != nullptr) { - ename_string = std::string(buffer); - } -#endif - return ename_string; -} - -} // namespace detail - - - -// Use one of these on all error classes. -// These are temporary and are undef'd at the end of this file. -#define CLI11_ERROR_DEF(parent, name) \ - protected: \ - name(std::string ename, std::string msg, int exit_code) : parent(std::move(ename), std::move(msg), exit_code) {} \ - name(std::string ename, std::string msg, ExitCodes exit_code) \ - : parent(std::move(ename), std::move(msg), exit_code) {} \ - \ - public: \ - name(std::string msg, ExitCodes exit_code) : parent(#name, std::move(msg), exit_code) {} \ - name(std::string msg, int exit_code) : parent(#name, std::move(msg), exit_code) {} - -// This is added after the one above if a class is used directly and builds its own message -#define CLI11_ERROR_SIMPLE(name) \ - explicit name(std::string msg) : name(#name, msg, ExitCodes::name) {} - -/// These codes are part of every error in CLI. They can be obtained from e using e.exit_code or as a quick shortcut, -/// int values from e.get_error_code(). -enum class ExitCodes { - Success = 0, - IncorrectConstruction = 100, - BadNameString, - OptionAlreadyAdded, - FileError, - ConversionError, - ValidationError, - RequiredError, - RequiresError, - ExcludesError, - ExtrasError, - ConfigError, - InvalidError, - HorribleError, - OptionNotFound, - ArgumentMismatch, - BaseClass = 127 -}; - -// Error definitions - -/// @defgroup error_group Errors -/// @brief Errors thrown by CLI11 -/// -/// These are the errors that can be thrown. Some of them, like CLI::Success, are not really errors. -/// @{ - -/// All errors derive from this one -class Error : public std::runtime_error { - int actual_exit_code; - std::string error_name{"Error"}; - - public: - CLI11_NODISCARD int get_exit_code() const { return actual_exit_code; } - - CLI11_NODISCARD std::string get_name() const { return error_name; } - - Error(std::string name, std::string msg, int exit_code = static_cast(ExitCodes::BaseClass)) - : runtime_error(msg), actual_exit_code(exit_code), error_name(std::move(name)) {} - - Error(std::string name, std::string msg, ExitCodes exit_code) : Error(name, msg, static_cast(exit_code)) {} -}; - -// Note: Using Error::Error constructors does not work on GCC 4.7 - -/// Construction errors (not in parsing) -class ConstructionError : public Error { - CLI11_ERROR_DEF(Error, ConstructionError) -}; - -/// Thrown when an option is set to conflicting values (non-vector and multi args, for example) -class IncorrectConstruction : public ConstructionError { - CLI11_ERROR_DEF(ConstructionError, IncorrectConstruction) - CLI11_ERROR_SIMPLE(IncorrectConstruction) - static IncorrectConstruction PositionalFlag(std::string name) { - return IncorrectConstruction(name + ": Flags cannot be positional"); - } - static IncorrectConstruction Set0Opt(std::string name) { - return IncorrectConstruction(name + ": Cannot set 0 expected, use a flag instead"); - } - static IncorrectConstruction SetFlag(std::string name) { - return IncorrectConstruction(name + ": Cannot set an expected number for flags"); - } - static IncorrectConstruction ChangeNotVector(std::string name) { - return IncorrectConstruction(name + ": You can only change the expected arguments for vectors"); - } - static IncorrectConstruction AfterMultiOpt(std::string name) { - return IncorrectConstruction( - name + ": You can't change expected arguments after you've changed the multi option policy!"); - } - static IncorrectConstruction MissingOption(std::string name) { - return IncorrectConstruction("Option " + name + " is not defined"); - } - static IncorrectConstruction MultiOptionPolicy(std::string name) { - return IncorrectConstruction(name + ": multi_option_policy only works for flags and exact value options"); - } -}; - -/// Thrown on construction of a bad name -class BadNameString : public ConstructionError { - CLI11_ERROR_DEF(ConstructionError, BadNameString) - CLI11_ERROR_SIMPLE(BadNameString) - static BadNameString OneCharName(std::string name) { return BadNameString("Invalid one char name: " + name); } - static BadNameString MissingDash(std::string name) { - return BadNameString("Long names strings require 2 dashes " + name); - } - static BadNameString BadLongName(std::string name) { return BadNameString("Bad long name: " + name); } - static BadNameString BadPositionalName(std::string name) { - return BadNameString("Invalid positional Name: " + name); - } - static BadNameString DashesOnly(std::string name) { - return BadNameString("Must have a name, not just dashes: " + name); - } - static BadNameString MultiPositionalNames(std::string name) { - return BadNameString("Only one positional name allowed, remove: " + name); - } -}; - -/// Thrown when an option already exists -class OptionAlreadyAdded : public ConstructionError { - CLI11_ERROR_DEF(ConstructionError, OptionAlreadyAdded) - explicit OptionAlreadyAdded(std::string name) - : OptionAlreadyAdded(name + " is already added", ExitCodes::OptionAlreadyAdded) {} - static OptionAlreadyAdded Requires(std::string name, std::string other) { - return {name + " requires " + other, ExitCodes::OptionAlreadyAdded}; - } - static OptionAlreadyAdded Excludes(std::string name, std::string other) { - return {name + " excludes " + other, ExitCodes::OptionAlreadyAdded}; - } -}; - -// Parsing errors - -/// Anything that can error in Parse -class ParseError : public Error { - CLI11_ERROR_DEF(Error, ParseError) -}; - -// Not really "errors" - -/// This is a successful completion on parsing, supposed to exit -class Success : public ParseError { - CLI11_ERROR_DEF(ParseError, Success) - Success() : Success("Successfully completed, should be caught and quit", ExitCodes::Success) {} -}; - -/// -h or --help on command line -class CallForHelp : public Success { - CLI11_ERROR_DEF(Success, CallForHelp) - CallForHelp() : CallForHelp("This should be caught in your main function, see examples", ExitCodes::Success) {} -}; - -/// Usually something like --help-all on command line -class CallForAllHelp : public Success { - CLI11_ERROR_DEF(Success, CallForAllHelp) - CallForAllHelp() - : CallForAllHelp("This should be caught in your main function, see examples", ExitCodes::Success) {} -}; - -/// -v or --version on command line -class CallForVersion : public Success { - CLI11_ERROR_DEF(Success, CallForVersion) - CallForVersion() - : CallForVersion("This should be caught in your main function, see examples", ExitCodes::Success) {} -}; - -/// Does not output a diagnostic in CLI11_PARSE, but allows main() to return with a specific error code. -class RuntimeError : public ParseError { - CLI11_ERROR_DEF(ParseError, RuntimeError) - explicit RuntimeError(int exit_code = 1) : RuntimeError("Runtime error", exit_code) {} -}; - -/// Thrown when parsing an INI file and it is missing -class FileError : public ParseError { - CLI11_ERROR_DEF(ParseError, FileError) - CLI11_ERROR_SIMPLE(FileError) - static FileError Missing(std::string name) { return FileError(name + " was not readable (missing?)"); } -}; - -/// Thrown when conversion call back fails, such as when an int fails to coerce to a string -class ConversionError : public ParseError { - CLI11_ERROR_DEF(ParseError, ConversionError) - CLI11_ERROR_SIMPLE(ConversionError) - ConversionError(std::string member, std::string name) - : ConversionError("The value " + member + " is not an allowed value for " + name) {} - ConversionError(std::string name, std::vector results) - : ConversionError("Could not convert: " + name + " = " + detail::join(results)) {} - static ConversionError TooManyInputsFlag(std::string name) { - return ConversionError(name + ": too many inputs for a flag"); - } - static ConversionError TrueFalse(std::string name) { - return ConversionError(name + ": Should be true/false or a number"); - } -}; - -/// Thrown when validation of results fails -class ValidationError : public ParseError { - CLI11_ERROR_DEF(ParseError, ValidationError) - CLI11_ERROR_SIMPLE(ValidationError) - explicit ValidationError(std::string name, std::string msg) : ValidationError(name + ": " + msg) {} -}; - -/// Thrown when a required option is missing -class RequiredError : public ParseError { - CLI11_ERROR_DEF(ParseError, RequiredError) - explicit RequiredError(std::string name) : RequiredError(name + " is required", ExitCodes::RequiredError) {} - static RequiredError Subcommand(std::size_t min_subcom) { - if(min_subcom == 1) { - return RequiredError("A subcommand"); - } - return {"Requires at least " + std::to_string(min_subcom) + " subcommands", ExitCodes::RequiredError}; - } - static RequiredError - Option(std::size_t min_option, std::size_t max_option, std::size_t used, const std::string &option_list) { - if((min_option == 1) && (max_option == 1) && (used == 0)) - return RequiredError("Exactly 1 option from [" + option_list + "]"); - if((min_option == 1) && (max_option == 1) && (used > 1)) { - return {"Exactly 1 option from [" + option_list + "] is required and " + std::to_string(used) + - " were given", - ExitCodes::RequiredError}; - } - if((min_option == 1) && (used == 0)) - return RequiredError("At least 1 option from [" + option_list + "]"); - if(used < min_option) { - return {"Requires at least " + std::to_string(min_option) + " options used and only " + - std::to_string(used) + "were given from [" + option_list + "]", - ExitCodes::RequiredError}; - } - if(max_option == 1) - return {"Requires at most 1 options be given from [" + option_list + "]", ExitCodes::RequiredError}; - - return {"Requires at most " + std::to_string(max_option) + " options be used and " + std::to_string(used) + - "were given from [" + option_list + "]", - ExitCodes::RequiredError}; - } -}; - -/// Thrown when the wrong number of arguments has been received -class ArgumentMismatch : public ParseError { - CLI11_ERROR_DEF(ParseError, ArgumentMismatch) - CLI11_ERROR_SIMPLE(ArgumentMismatch) - ArgumentMismatch(std::string name, int expected, std::size_t received) - : ArgumentMismatch(expected > 0 ? ("Expected exactly " + std::to_string(expected) + " arguments to " + name + - ", got " + std::to_string(received)) - : ("Expected at least " + std::to_string(-expected) + " arguments to " + name + - ", got " + std::to_string(received)), - ExitCodes::ArgumentMismatch) {} - - static ArgumentMismatch AtLeast(std::string name, int num, std::size_t received) { - return ArgumentMismatch(name + ": At least " + std::to_string(num) + " required but received " + - std::to_string(received)); - } - static ArgumentMismatch AtMost(std::string name, int num, std::size_t received) { - return ArgumentMismatch(name + ": At Most " + std::to_string(num) + " required but received " + - std::to_string(received)); - } - static ArgumentMismatch TypedAtLeast(std::string name, int num, std::string type) { - return ArgumentMismatch(name + ": " + std::to_string(num) + " required " + type + " missing"); - } - static ArgumentMismatch FlagOverride(std::string name) { - return ArgumentMismatch(name + " was given a disallowed flag override"); - } - static ArgumentMismatch PartialType(std::string name, int num, std::string type) { - return ArgumentMismatch(name + ": " + type + " only partially specified: " + std::to_string(num) + - " required for each element"); - } -}; - -/// Thrown when a requires option is missing -class RequiresError : public ParseError { - CLI11_ERROR_DEF(ParseError, RequiresError) - RequiresError(std::string curname, std::string subname) - : RequiresError(curname + " requires " + subname, ExitCodes::RequiresError) {} -}; - -/// Thrown when an excludes option is present -class ExcludesError : public ParseError { - CLI11_ERROR_DEF(ParseError, ExcludesError) - ExcludesError(std::string curname, std::string subname) - : ExcludesError(curname + " excludes " + subname, ExitCodes::ExcludesError) {} -}; - -/// Thrown when too many positionals or options are found -class ExtrasError : public ParseError { - CLI11_ERROR_DEF(ParseError, ExtrasError) - explicit ExtrasError(std::vector args) - : ExtrasError((args.size() > 1 ? "The following arguments were not expected: " - : "The following argument was not expected: ") + - detail::rjoin(args, " "), - ExitCodes::ExtrasError) {} - ExtrasError(const std::string &name, std::vector args) - : ExtrasError(name, - (args.size() > 1 ? "The following arguments were not expected: " - : "The following argument was not expected: ") + - detail::rjoin(args, " "), - ExitCodes::ExtrasError) {} -}; - -/// Thrown when extra values are found in an INI file -class ConfigError : public ParseError { - CLI11_ERROR_DEF(ParseError, ConfigError) - CLI11_ERROR_SIMPLE(ConfigError) - static ConfigError Extras(std::string item) { return ConfigError("INI was not able to parse " + item); } - static ConfigError NotConfigurable(std::string item) { - return ConfigError(item + ": This option is not allowed in a configuration file"); - } -}; - -/// Thrown when validation fails before parsing -class InvalidError : public ParseError { - CLI11_ERROR_DEF(ParseError, InvalidError) - explicit InvalidError(std::string name) - : InvalidError(name + ": Too many positional arguments with unlimited expected args", ExitCodes::InvalidError) { - } -}; - -/// This is just a safety check to verify selection and parsing match - you should not ever see it -/// Strings are directly added to this error, but again, it should never be seen. -class HorribleError : public ParseError { - CLI11_ERROR_DEF(ParseError, HorribleError) - CLI11_ERROR_SIMPLE(HorribleError) -}; - -// After parsing - -/// Thrown when counting a non-existent option -class OptionNotFound : public Error { - CLI11_ERROR_DEF(Error, OptionNotFound) - explicit OptionNotFound(std::string name) : OptionNotFound(name + " not found", ExitCodes::OptionNotFound) {} -}; - -#undef CLI11_ERROR_DEF -#undef CLI11_ERROR_SIMPLE - -/// @} - - - - -// Type tools - -// Utilities for type enabling -namespace detail { -// Based generally on https://rmf.io/cxx11/almost-static-if -/// Simple empty scoped class -enum class enabler {}; - -/// An instance to use in EnableIf -constexpr enabler dummy = {}; -} // namespace detail - -/// A copy of enable_if_t from C++14, compatible with C++11. -/// -/// We could check to see if C++14 is being used, but it does not hurt to redefine this -/// (even Google does this: https://github.com/google/skia/blob/main/include/private/SkTLogic.h) -/// It is not in the std namespace anyway, so no harm done. -template using enable_if_t = typename std::enable_if::type; - -/// A copy of std::void_t from C++17 (helper for C++11 and C++14) -template struct make_void { - using type = void; -}; - -/// A copy of std::void_t from C++17 - same reasoning as enable_if_t, it does not hurt to redefine -template using void_t = typename make_void::type; - -/// A copy of std::conditional_t from C++14 - same reasoning as enable_if_t, it does not hurt to redefine -template using conditional_t = typename std::conditional::type; - -/// Check to see if something is bool (fail check by default) -template struct is_bool : std::false_type {}; - -/// Check to see if something is bool (true if actually a bool) -template <> struct is_bool : std::true_type {}; - -/// Check to see if something is a shared pointer -template struct is_shared_ptr : std::false_type {}; - -/// Check to see if something is a shared pointer (True if really a shared pointer) -template struct is_shared_ptr> : std::true_type {}; - -/// Check to see if something is a shared pointer (True if really a shared pointer) -template struct is_shared_ptr> : std::true_type {}; - -/// Check to see if something is copyable pointer -template struct is_copyable_ptr { - static bool const value = is_shared_ptr::value || std::is_pointer::value; -}; - -/// This can be specialized to override the type deduction for IsMember. -template struct IsMemberType { - using type = T; -}; - -/// The main custom type needed here is const char * should be a string. -template <> struct IsMemberType { - using type = std::string; -}; - -namespace detail { - -// These are utilities for IsMember and other transforming objects - -/// Handy helper to access the element_type generically. This is not part of is_copyable_ptr because it requires that -/// pointer_traits be valid. - -/// not a pointer -template struct element_type { - using type = T; -}; - -template struct element_type::value>::type> { - using type = typename std::pointer_traits::element_type; -}; - -/// Combination of the element type and value type - remove pointer (including smart pointers) and get the value_type of -/// the container -template struct element_value_type { - using type = typename element_type::type::value_type; -}; - -/// Adaptor for set-like structure: This just wraps a normal container in a few utilities that do almost nothing. -template struct pair_adaptor : std::false_type { - using value_type = typename T::value_type; - using first_type = typename std::remove_const::type; - using second_type = typename std::remove_const::type; - - /// Get the first value (really just the underlying value) - template static auto first(Q &&pair_value) -> decltype(std::forward(pair_value)) { - return std::forward(pair_value); - } - /// Get the second value (really just the underlying value) - template static auto second(Q &&pair_value) -> decltype(std::forward(pair_value)) { - return std::forward(pair_value); - } -}; - -/// Adaptor for map-like structure (true version, must have key_type and mapped_type). -/// This wraps a mapped container in a few utilities access it in a general way. -template -struct pair_adaptor< - T, - conditional_t, void>> - : std::true_type { - using value_type = typename T::value_type; - using first_type = typename std::remove_const::type; - using second_type = typename std::remove_const::type; - - /// Get the first value (really just the underlying value) - template static auto first(Q &&pair_value) -> decltype(std::get<0>(std::forward(pair_value))) { - return std::get<0>(std::forward(pair_value)); - } - /// Get the second value (really just the underlying value) - template static auto second(Q &&pair_value) -> decltype(std::get<1>(std::forward(pair_value))) { - return std::get<1>(std::forward(pair_value)); - } -}; - -// Warning is suppressed due to "bug" in gcc<5.0 and gcc 7.0 with c++17 enabled that generates a Wnarrowing warning -// in the unevaluated context even if the function that was using this wasn't used. The standard says narrowing in -// brace initialization shouldn't be allowed but for backwards compatibility gcc allows it in some contexts. It is a -// little fuzzy what happens in template constructs and I think that was something GCC took a little while to work out. -// But regardless some versions of gcc generate a warning when they shouldn't from the following code so that should be -// suppressed -#ifdef __GNUC__ -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wnarrowing" -#endif -// check for constructibility from a specific type and copy assignable used in the parse detection -template class is_direct_constructible { - template - static auto test(int, std::true_type) -> decltype( -// NVCC warns about narrowing conversions here -#ifdef __CUDACC__ -#ifdef __NVCC_DIAG_PRAGMA_SUPPORT__ -#pragma nv_diag_suppress 2361 -#else -#pragma diag_suppress 2361 -#endif -#endif - TT{std::declval()} -#ifdef __CUDACC__ -#ifdef __NVCC_DIAG_PRAGMA_SUPPORT__ -#pragma nv_diag_default 2361 -#else -#pragma diag_default 2361 -#endif -#endif - , - std::is_move_assignable()); - - template static auto test(int, std::false_type) -> std::false_type; - - template static auto test(...) -> std::false_type; - - public: - static constexpr bool value = decltype(test(0, typename std::is_constructible::type()))::value; -}; -#ifdef __GNUC__ -#pragma GCC diagnostic pop -#endif - -// Check for output streamability -// Based on https://stackoverflow.com/questions/22758291/how-can-i-detect-if-a-type-can-be-streamed-to-an-stdostream - -template class is_ostreamable { - template - static auto test(int) -> decltype(std::declval() << std::declval(), std::true_type()); - - template static auto test(...) -> std::false_type; - - public: - static constexpr bool value = decltype(test(0))::value; -}; - -/// Check for input streamability -template class is_istreamable { - template - static auto test(int) -> decltype(std::declval() >> std::declval(), std::true_type()); - - template static auto test(...) -> std::false_type; - - public: - static constexpr bool value = decltype(test(0))::value; -}; - -/// Check for complex -template class is_complex { - template - static auto test(int) -> decltype(std::declval().real(), std::declval().imag(), std::true_type()); - - template static auto test(...) -> std::false_type; - - public: - static constexpr bool value = decltype(test(0))::value; -}; - -/// Templated operation to get a value from a stream -template ::value, detail::enabler> = detail::dummy> -bool from_stream(const std::string &istring, T &obj) { - std::istringstream is; - is.str(istring); - is >> obj; - return !is.fail() && !is.rdbuf()->in_avail(); -} - -template ::value, detail::enabler> = detail::dummy> -bool from_stream(const std::string & /*istring*/, T & /*obj*/) { - return false; -} - -// check to see if an object is a mutable container (fail by default) -template struct is_mutable_container : std::false_type {}; - -/// type trait to test if a type is a mutable container meaning it has a value_type, it has an iterator, a clear, and -/// end methods and an insert function. And for our purposes we exclude std::string and types that can be constructed -/// from a std::string -template -struct is_mutable_container< - T, - conditional_t().end()), - decltype(std::declval().clear()), - decltype(std::declval().insert(std::declval().end())>(), - std::declval()))>, - void>> : public conditional_t::value || - std::is_constructible::value, - std::false_type, - std::true_type> {}; - -// check to see if an object is a mutable container (fail by default) -template struct is_readable_container : std::false_type {}; - -/// type trait to test if a type is a container meaning it has a value_type, it has an iterator, a clear, and an end -/// methods and an insert function. And for our purposes we exclude std::string and types that can be constructed from -/// a std::string -template -struct is_readable_container< - T, - conditional_t().end()), decltype(std::declval().begin())>, void>> - : public std::true_type {}; - -// check to see if an object is a wrapper (fail by default) -template struct is_wrapper : std::false_type {}; - -// check if an object is a wrapper (it has a value_type defined) -template -struct is_wrapper, void>> : public std::true_type {}; - -// Check for tuple like types, as in classes with a tuple_size type trait -template class is_tuple_like { - template - // static auto test(int) - // -> decltype(std::conditional<(std::tuple_size::value > 0), std::true_type, std::false_type>::type()); - static auto test(int) -> decltype(std::tuple_size::type>::value, std::true_type{}); - template static auto test(...) -> std::false_type; - - public: - static constexpr bool value = decltype(test(0))::value; -}; - -/// Convert an object to a string (directly forward if this can become a string) -template ::value, detail::enabler> = detail::dummy> -auto to_string(T &&value) -> decltype(std::forward(value)) { - return std::forward(value); -} - -/// Construct a string from the object -template ::value && !std::is_convertible::value, - detail::enabler> = detail::dummy> -std::string to_string(const T &value) { - return std::string(value); // NOLINT(google-readability-casting) -} - -/// Convert an object to a string (streaming must be supported for that type) -template ::value && !std::is_constructible::value && - is_ostreamable::value, - detail::enabler> = detail::dummy> -std::string to_string(T &&value) { - std::stringstream stream; - stream << value; - return stream.str(); -} - -/// If conversion is not supported, return an empty string (streaming is not supported for that type) -template ::value && !is_ostreamable::value && - !is_readable_container::type>::value, - detail::enabler> = detail::dummy> -std::string to_string(T &&) { - return {}; -} - -/// convert a readable container to a string -template ::value && !is_ostreamable::value && - is_readable_container::value, - detail::enabler> = detail::dummy> -std::string to_string(T &&variable) { - auto cval = variable.begin(); - auto end = variable.end(); - if(cval == end) { - return {"{}"}; - } - std::vector defaults; - while(cval != end) { - defaults.emplace_back(CLI::detail::to_string(*cval)); - ++cval; - } - return {"[" + detail::join(defaults) + "]"}; -} - -/// special template overload -template ::value, detail::enabler> = detail::dummy> -auto checked_to_string(T &&value) -> decltype(to_string(std::forward(value))) { - return to_string(std::forward(value)); -} - -/// special template overload -template ::value, detail::enabler> = detail::dummy> -std::string checked_to_string(T &&) { - return std::string{}; -} -/// get a string as a convertible value for arithmetic types -template ::value, detail::enabler> = detail::dummy> -std::string value_string(const T &value) { - return std::to_string(value); -} -/// get a string as a convertible value for enumerations -template ::value, detail::enabler> = detail::dummy> -std::string value_string(const T &value) { - return std::to_string(static_cast::type>(value)); -} -/// for other types just use the regular to_string function -template ::value && !std::is_arithmetic::value, detail::enabler> = detail::dummy> -auto value_string(const T &value) -> decltype(to_string(value)) { - return to_string(value); -} - -/// template to get the underlying value type if it exists or use a default -template struct wrapped_type { - using type = def; -}; - -/// Type size for regular object types that do not look like a tuple -template struct wrapped_type::value>::type> { - using type = typename T::value_type; -}; - -/// This will only trigger for actual void type -template struct type_count_base { - static const int value{0}; -}; - -/// Type size for regular object types that do not look like a tuple -template -struct type_count_base::value && !is_mutable_container::value && - !std::is_void::value>::type> { - static constexpr int value{1}; -}; - -/// the base tuple size -template -struct type_count_base::value && !is_mutable_container::value>::type> { - static constexpr int value{std::tuple_size::value}; -}; - -/// Type count base for containers is the type_count_base of the individual element -template struct type_count_base::value>::type> { - static constexpr int value{type_count_base::value}; -}; - -/// Set of overloads to get the type size of an object - -/// forward declare the subtype_count structure -template struct subtype_count; - -/// forward declare the subtype_count_min structure -template struct subtype_count_min; - -/// This will only trigger for actual void type -template struct type_count { - static const int value{0}; -}; - -/// Type size for regular object types that do not look like a tuple -template -struct type_count::value && !is_tuple_like::value && !is_complex::value && - !std::is_void::value>::type> { - static constexpr int value{1}; -}; - -/// Type size for complex since it sometimes looks like a wrapper -template struct type_count::value>::type> { - static constexpr int value{2}; -}; - -/// Type size of types that are wrappers,except complex and tuples(which can also be wrappers sometimes) -template struct type_count::value>::type> { - static constexpr int value{subtype_count::value}; -}; - -/// Type size of types that are wrappers,except containers complex and tuples(which can also be wrappers sometimes) -template -struct type_count::value && !is_complex::value && !is_tuple_like::value && - !is_mutable_container::value>::type> { - static constexpr int value{type_count::value}; -}; - -/// 0 if the index > tuple size -template -constexpr typename std::enable_if::value, int>::type tuple_type_size() { - return 0; -} - -/// Recursively generate the tuple type name -template - constexpr typename std::enable_if < I::value, int>::type tuple_type_size() { - return subtype_count::type>::value + tuple_type_size(); -} - -/// Get the type size of the sum of type sizes for all the individual tuple types -template struct type_count::value>::type> { - static constexpr int value{tuple_type_size()}; -}; - -/// definition of subtype count -template struct subtype_count { - static constexpr int value{is_mutable_container::value ? expected_max_vector_size : type_count::value}; -}; - -/// This will only trigger for actual void type -template struct type_count_min { - static const int value{0}; -}; - -/// Type size for regular object types that do not look like a tuple -template -struct type_count_min< - T, - typename std::enable_if::value && !is_tuple_like::value && !is_wrapper::value && - !is_complex::value && !std::is_void::value>::type> { - static constexpr int value{type_count::value}; -}; - -/// Type size for complex since it sometimes looks like a wrapper -template struct type_count_min::value>::type> { - static constexpr int value{1}; -}; - -/// Type size min of types that are wrappers,except complex and tuples(which can also be wrappers sometimes) -template -struct type_count_min< - T, - typename std::enable_if::value && !is_complex::value && !is_tuple_like::value>::type> { - static constexpr int value{subtype_count_min::value}; -}; - -/// 0 if the index > tuple size -template -constexpr typename std::enable_if::value, int>::type tuple_type_size_min() { - return 0; -} - -/// Recursively generate the tuple type name -template - constexpr typename std::enable_if < I::value, int>::type tuple_type_size_min() { - return subtype_count_min::type>::value + tuple_type_size_min(); -} - -/// Get the type size of the sum of type sizes for all the individual tuple types -template struct type_count_min::value>::type> { - static constexpr int value{tuple_type_size_min()}; -}; - -/// definition of subtype count -template struct subtype_count_min { - static constexpr int value{is_mutable_container::value - ? ((type_count::value < expected_max_vector_size) ? type_count::value : 0) - : type_count_min::value}; -}; - -/// This will only trigger for actual void type -template struct expected_count { - static const int value{0}; -}; - -/// For most types the number of expected items is 1 -template -struct expected_count::value && !is_wrapper::value && - !std::is_void::value>::type> { - static constexpr int value{1}; -}; -/// number of expected items in a vector -template struct expected_count::value>::type> { - static constexpr int value{expected_max_vector_size}; -}; - -/// number of expected items in a vector -template -struct expected_count::value && is_wrapper::value>::type> { - static constexpr int value{expected_count::value}; -}; - -// Enumeration of the different supported categorizations of objects -enum class object_category : int { - char_value = 1, - integral_value = 2, - unsigned_integral = 4, - enumeration = 6, - boolean_value = 8, - floating_point = 10, - number_constructible = 12, - double_constructible = 14, - integer_constructible = 16, - // string like types - string_assignable = 23, - string_constructible = 24, - wstring_assignable = 25, - wstring_constructible = 26, - other = 45, - // special wrapper or container types - wrapper_value = 50, - complex_number = 60, - tuple_value = 70, - container_value = 80, - -}; - -/// Set of overloads to classify an object according to type - -/// some type that is not otherwise recognized -template struct classify_object { - static constexpr object_category value{object_category::other}; -}; - -/// Signed integers -template -struct classify_object< - T, - typename std::enable_if::value && !std::is_same::value && std::is_signed::value && - !is_bool::value && !std::is_enum::value>::type> { - static constexpr object_category value{object_category::integral_value}; -}; - -/// Unsigned integers -template -struct classify_object::value && std::is_unsigned::value && - !std::is_same::value && !is_bool::value>::type> { - static constexpr object_category value{object_category::unsigned_integral}; -}; - -/// single character values -template -struct classify_object::value && !std::is_enum::value>::type> { - static constexpr object_category value{object_category::char_value}; -}; - -/// Boolean values -template struct classify_object::value>::type> { - static constexpr object_category value{object_category::boolean_value}; -}; - -/// Floats -template struct classify_object::value>::type> { - static constexpr object_category value{object_category::floating_point}; -}; -#if defined _MSC_VER -// in MSVC wstring should take precedence if available this isn't as useful on other compilers due to the broader use of -// utf-8 encoding -#define WIDE_STRING_CHECK \ - !std::is_assignable::value && !std::is_constructible::value -#define STRING_CHECK true -#else -#define WIDE_STRING_CHECK true -#define STRING_CHECK !std::is_assignable::value && !std::is_constructible::value -#endif - -/// String and similar direct assignment -template -struct classify_object< - T, - typename std::enable_if::value && !std::is_integral::value && WIDE_STRING_CHECK && - std::is_assignable::value>::type> { - static constexpr object_category value{object_category::string_assignable}; -}; - -/// String and similar constructible and copy assignment -template -struct classify_object< - T, - typename std::enable_if::value && !std::is_integral::value && - !std::is_assignable::value && (type_count::value == 1) && - WIDE_STRING_CHECK && std::is_constructible::value>::type> { - static constexpr object_category value{object_category::string_constructible}; -}; - -/// Wide strings -template -struct classify_object::value && !std::is_integral::value && - STRING_CHECK && std::is_assignable::value>::type> { - static constexpr object_category value{object_category::wstring_assignable}; -}; - -template -struct classify_object< - T, - typename std::enable_if::value && !std::is_integral::value && - !std::is_assignable::value && (type_count::value == 1) && - STRING_CHECK && std::is_constructible::value>::type> { - static constexpr object_category value{object_category::wstring_constructible}; -}; - -/// Enumerations -template struct classify_object::value>::type> { - static constexpr object_category value{object_category::enumeration}; -}; - -template struct classify_object::value>::type> { - static constexpr object_category value{object_category::complex_number}; -}; - -/// Handy helper to contain a bunch of checks that rule out many common types (integers, string like, floating point, -/// vectors, and enumerations -template struct uncommon_type { - using type = typename std::conditional< - !std::is_floating_point::value && !std::is_integral::value && - !std::is_assignable::value && !std::is_constructible::value && - !std::is_assignable::value && !std::is_constructible::value && - !is_complex::value && !is_mutable_container::value && !std::is_enum::value, - std::true_type, - std::false_type>::type; - static constexpr bool value = type::value; -}; - -/// wrapper type -template -struct classify_object::value && is_wrapper::value && - !is_tuple_like::value && uncommon_type::value)>::type> { - static constexpr object_category value{object_category::wrapper_value}; -}; - -/// Assignable from double or int -template -struct classify_object::value && type_count::value == 1 && - !is_wrapper::value && is_direct_constructible::value && - is_direct_constructible::value>::type> { - static constexpr object_category value{object_category::number_constructible}; -}; - -/// Assignable from int -template -struct classify_object::value && type_count::value == 1 && - !is_wrapper::value && !is_direct_constructible::value && - is_direct_constructible::value>::type> { - static constexpr object_category value{object_category::integer_constructible}; -}; - -/// Assignable from double -template -struct classify_object::value && type_count::value == 1 && - !is_wrapper::value && is_direct_constructible::value && - !is_direct_constructible::value>::type> { - static constexpr object_category value{object_category::double_constructible}; -}; - -/// Tuple type -template -struct classify_object< - T, - typename std::enable_if::value && - ((type_count::value >= 2 && !is_wrapper::value) || - (uncommon_type::value && !is_direct_constructible::value && - !is_direct_constructible::value) || - (uncommon_type::value && type_count::value >= 2))>::type> { - static constexpr object_category value{object_category::tuple_value}; - // the condition on this class requires it be like a tuple, but on some compilers (like Xcode) tuples can be - // constructed from just the first element so tuples of can be constructed from a string, which - // could lead to issues so there are two variants of the condition, the first isolates things with a type size >=2 - // mainly to get tuples on Xcode with the exception of wrappers, the second is the main one and just separating out - // those cases that are caught by other object classifications -}; - -/// container type -template struct classify_object::value>::type> { - static constexpr object_category value{object_category::container_value}; -}; - -// Type name print - -/// Was going to be based on -/// http://stackoverflow.com/questions/1055452/c-get-name-of-type-in-template -/// But this is cleaner and works better in this case - -template ::value == object_category::char_value, detail::enabler> = detail::dummy> -constexpr const char *type_name() { - return "CHAR"; -} - -template ::value == object_category::integral_value || - classify_object::value == object_category::integer_constructible, - detail::enabler> = detail::dummy> -constexpr const char *type_name() { - return "INT"; -} - -template ::value == object_category::unsigned_integral, detail::enabler> = detail::dummy> -constexpr const char *type_name() { - return "UINT"; -} - -template ::value == object_category::floating_point || - classify_object::value == object_category::number_constructible || - classify_object::value == object_category::double_constructible, - detail::enabler> = detail::dummy> -constexpr const char *type_name() { - return "FLOAT"; -} - -/// Print name for enumeration types -template ::value == object_category::enumeration, detail::enabler> = detail::dummy> -constexpr const char *type_name() { - return "ENUM"; -} - -/// Print name for enumeration types -template ::value == object_category::boolean_value, detail::enabler> = detail::dummy> -constexpr const char *type_name() { - return "BOOLEAN"; -} - -/// Print name for enumeration types -template ::value == object_category::complex_number, detail::enabler> = detail::dummy> -constexpr const char *type_name() { - return "COMPLEX"; -} - -/// Print for all other types -template ::value >= object_category::string_assignable && - classify_object::value <= object_category::other, - detail::enabler> = detail::dummy> -constexpr const char *type_name() { - return "TEXT"; -} -/// typename for tuple value -template ::value == object_category::tuple_value && type_count_base::value >= 2, - detail::enabler> = detail::dummy> -std::string type_name(); // forward declaration - -/// Generate type name for a wrapper or container value -template ::value == object_category::container_value || - classify_object::value == object_category::wrapper_value, - detail::enabler> = detail::dummy> -std::string type_name(); // forward declaration - -/// Print name for single element tuple types -template ::value == object_category::tuple_value && type_count_base::value == 1, - detail::enabler> = detail::dummy> -inline std::string type_name() { - return type_name::type>::type>(); -} - -/// Empty string if the index > tuple size -template -inline typename std::enable_if::value, std::string>::type tuple_name() { - return std::string{}; -} - -/// Recursively generate the tuple type name -template -inline typename std::enable_if<(I < type_count_base::value), std::string>::type tuple_name() { - auto str = std::string{type_name::type>::type>()} + ',' + - tuple_name(); - if(str.back() == ',') - str.pop_back(); - return str; -} - -/// Print type name for tuples with 2 or more elements -template ::value == object_category::tuple_value && type_count_base::value >= 2, - detail::enabler>> -inline std::string type_name() { - auto tname = std::string(1, '[') + tuple_name(); - tname.push_back(']'); - return tname; -} - -/// get the type name for a type that has a value_type member -template ::value == object_category::container_value || - classify_object::value == object_category::wrapper_value, - detail::enabler>> -inline std::string type_name() { - return type_name(); -} - -// Lexical cast - -/// Convert to an unsigned integral -template ::value, detail::enabler> = detail::dummy> -bool integral_conversion(const std::string &input, T &output) noexcept { - if(input.empty() || input.front() == '-') { - return false; - } - char *val{nullptr}; - errno = 0; - std::uint64_t output_ll = std::strtoull(input.c_str(), &val, 0); - if(errno == ERANGE) { - return false; - } - output = static_cast(output_ll); - if(val == (input.c_str() + input.size()) && static_cast(output) == output_ll) { - return true; - } - val = nullptr; - std::int64_t output_sll = std::strtoll(input.c_str(), &val, 0); - if(val == (input.c_str() + input.size())) { - output = (output_sll < 0) ? static_cast(0) : static_cast(output_sll); - return (static_cast(output) == output_sll); - } - // remove separators - if(input.find_first_of("_'") != std::string::npos) { - std::string nstring = input; - nstring.erase(std::remove(nstring.begin(), nstring.end(), '_'), nstring.end()); - nstring.erase(std::remove(nstring.begin(), nstring.end(), '\''), nstring.end()); - return integral_conversion(nstring, output); - } - if(input.compare(0, 2, "0o") == 0) { - val = nullptr; - errno = 0; - output_ll = std::strtoull(input.c_str() + 2, &val, 8); - if(errno == ERANGE) { - return false; - } - output = static_cast(output_ll); - return (val == (input.c_str() + input.size()) && static_cast(output) == output_ll); - } - if(input.compare(0, 2, "0b") == 0) { - val = nullptr; - errno = 0; - output_ll = std::strtoull(input.c_str() + 2, &val, 2); - if(errno == ERANGE) { - return false; - } - output = static_cast(output_ll); - return (val == (input.c_str() + input.size()) && static_cast(output) == output_ll); - } - return false; -} - -/// Convert to a signed integral -template ::value, detail::enabler> = detail::dummy> -bool integral_conversion(const std::string &input, T &output) noexcept { - if(input.empty()) { - return false; - } - char *val = nullptr; - errno = 0; - std::int64_t output_ll = std::strtoll(input.c_str(), &val, 0); - if(errno == ERANGE) { - return false; - } - output = static_cast(output_ll); - if(val == (input.c_str() + input.size()) && static_cast(output) == output_ll) { - return true; - } - if(input == "true") { - // this is to deal with a few oddities with flags and wrapper int types - output = static_cast(1); - return true; - } - // remove separators - if(input.find_first_of("_'") != std::string::npos) { - std::string nstring = input; - nstring.erase(std::remove(nstring.begin(), nstring.end(), '_'), nstring.end()); - nstring.erase(std::remove(nstring.begin(), nstring.end(), '\''), nstring.end()); - return integral_conversion(nstring, output); - } - if(input.compare(0, 2, "0o") == 0) { - val = nullptr; - errno = 0; - output_ll = std::strtoll(input.c_str() + 2, &val, 8); - if(errno == ERANGE) { - return false; - } - output = static_cast(output_ll); - return (val == (input.c_str() + input.size()) && static_cast(output) == output_ll); - } - if(input.compare(0, 2, "0b") == 0) { - val = nullptr; - errno = 0; - output_ll = std::strtoll(input.c_str() + 2, &val, 2); - if(errno == ERANGE) { - return false; - } - output = static_cast(output_ll); - return (val == (input.c_str() + input.size()) && static_cast(output) == output_ll); - } - return false; -} - -/// Convert a flag into an integer value typically binary flags sets errno to nonzero if conversion failed -inline std::int64_t to_flag_value(std::string val) noexcept { - static const std::string trueString("true"); - static const std::string falseString("false"); - if(val == trueString) { - return 1; - } - if(val == falseString) { - return -1; - } - val = detail::to_lower(val); - std::int64_t ret = 0; - if(val.size() == 1) { - if(val[0] >= '1' && val[0] <= '9') { - return (static_cast(val[0]) - '0'); - } - switch(val[0]) { - case '0': - case 'f': - case 'n': - case '-': - ret = -1; - break; - case 't': - case 'y': - case '+': - ret = 1; - break; - default: - errno = EINVAL; - return -1; - } - return ret; - } - if(val == trueString || val == "on" || val == "yes" || val == "enable") { - ret = 1; - } else if(val == falseString || val == "off" || val == "no" || val == "disable") { - ret = -1; - } else { - char *loc_ptr{nullptr}; - ret = std::strtoll(val.c_str(), &loc_ptr, 0); - if(loc_ptr != (val.c_str() + val.size()) && errno == 0) { - errno = EINVAL; - } - } - return ret; -} - -/// Integer conversion -template ::value == object_category::integral_value || - classify_object::value == object_category::unsigned_integral, - detail::enabler> = detail::dummy> -bool lexical_cast(const std::string &input, T &output) { - return integral_conversion(input, output); -} - -/// char values -template ::value == object_category::char_value, detail::enabler> = detail::dummy> -bool lexical_cast(const std::string &input, T &output) { - if(input.size() == 1) { - output = static_cast(input[0]); - return true; - } - return integral_conversion(input, output); -} - -/// Boolean values -template ::value == object_category::boolean_value, detail::enabler> = detail::dummy> -bool lexical_cast(const std::string &input, T &output) { - errno = 0; - auto out = to_flag_value(input); - if(errno == 0) { - output = (out > 0); - } else if(errno == ERANGE) { - output = (input[0] != '-'); - } else { - return false; - } - return true; -} - -/// Floats -template ::value == object_category::floating_point, detail::enabler> = detail::dummy> -bool lexical_cast(const std::string &input, T &output) { - if(input.empty()) { - return false; - } - char *val = nullptr; - auto output_ld = std::strtold(input.c_str(), &val); - output = static_cast(output_ld); - if(val == (input.c_str() + input.size())) { - return true; - } - // remove separators - if(input.find_first_of("_'") != std::string::npos) { - std::string nstring = input; - nstring.erase(std::remove(nstring.begin(), nstring.end(), '_'), nstring.end()); - nstring.erase(std::remove(nstring.begin(), nstring.end(), '\''), nstring.end()); - return lexical_cast(nstring, output); - } - return false; -} - -/// complex -template ::value == object_category::complex_number, detail::enabler> = detail::dummy> -bool lexical_cast(const std::string &input, T &output) { - using XC = typename wrapped_type::type; - XC x{0.0}, y{0.0}; - auto str1 = input; - bool worked = false; - auto nloc = str1.find_last_of("+-"); - if(nloc != std::string::npos && nloc > 0) { - worked = lexical_cast(str1.substr(0, nloc), x); - str1 = str1.substr(nloc); - if(str1.back() == 'i' || str1.back() == 'j') - str1.pop_back(); - worked = worked && lexical_cast(str1, y); - } else { - if(str1.back() == 'i' || str1.back() == 'j') { - str1.pop_back(); - worked = lexical_cast(str1, y); - x = XC{0}; - } else { - worked = lexical_cast(str1, x); - y = XC{0}; - } - } - if(worked) { - output = T{x, y}; - return worked; - } - return from_stream(input, output); -} - -/// String and similar direct assignment -template ::value == object_category::string_assignable, detail::enabler> = detail::dummy> -bool lexical_cast(const std::string &input, T &output) { - output = input; - return true; -} - -/// String and similar constructible and copy assignment -template < - typename T, - enable_if_t::value == object_category::string_constructible, detail::enabler> = detail::dummy> -bool lexical_cast(const std::string &input, T &output) { - output = T(input); - return true; -} - -/// Wide strings -template < - typename T, - enable_if_t::value == object_category::wstring_assignable, detail::enabler> = detail::dummy> -bool lexical_cast(const std::string &input, T &output) { - output = widen(input); - return true; -} - -template < - typename T, - enable_if_t::value == object_category::wstring_constructible, detail::enabler> = detail::dummy> -bool lexical_cast(const std::string &input, T &output) { - output = T{widen(input)}; - return true; -} - -/// Enumerations -template ::value == object_category::enumeration, detail::enabler> = detail::dummy> -bool lexical_cast(const std::string &input, T &output) { - typename std::underlying_type::type val; - if(!integral_conversion(input, val)) { - return false; - } - output = static_cast(val); - return true; -} - -/// wrapper types -template ::value == object_category::wrapper_value && - std::is_assignable::value, - detail::enabler> = detail::dummy> -bool lexical_cast(const std::string &input, T &output) { - typename T::value_type val; - if(lexical_cast(input, val)) { - output = val; - return true; - } - return from_stream(input, output); -} - -template ::value == object_category::wrapper_value && - !std::is_assignable::value && std::is_assignable::value, - detail::enabler> = detail::dummy> -bool lexical_cast(const std::string &input, T &output) { - typename T::value_type val; - if(lexical_cast(input, val)) { - output = T{val}; - return true; - } - return from_stream(input, output); -} - -/// Assignable from double or int -template < - typename T, - enable_if_t::value == object_category::number_constructible, detail::enabler> = detail::dummy> -bool lexical_cast(const std::string &input, T &output) { - int val = 0; - if(integral_conversion(input, val)) { - output = T(val); - return true; - } - - double dval = 0.0; - if(lexical_cast(input, dval)) { - output = T{dval}; - return true; - } - - return from_stream(input, output); -} - -/// Assignable from int -template < - typename T, - enable_if_t::value == object_category::integer_constructible, detail::enabler> = detail::dummy> -bool lexical_cast(const std::string &input, T &output) { - int val = 0; - if(integral_conversion(input, val)) { - output = T(val); - return true; - } - return from_stream(input, output); -} - -/// Assignable from double -template < - typename T, - enable_if_t::value == object_category::double_constructible, detail::enabler> = detail::dummy> -bool lexical_cast(const std::string &input, T &output) { - double val = 0.0; - if(lexical_cast(input, val)) { - output = T{val}; - return true; - } - return from_stream(input, output); -} - -/// Non-string convertible from an int -template ::value == object_category::other && std::is_assignable::value, - detail::enabler> = detail::dummy> -bool lexical_cast(const std::string &input, T &output) { - int val = 0; - if(integral_conversion(input, val)) { -#ifdef _MSC_VER -#pragma warning(push) -#pragma warning(disable : 4800) -#endif - // with Atomic this could produce a warning due to the conversion but if atomic gets here it is an old style - // so will most likely still work - output = val; -#ifdef _MSC_VER -#pragma warning(pop) -#endif - return true; - } - // LCOV_EXCL_START - // This version of cast is only used for odd cases in an older compilers the fail over - // from_stream is tested elsewhere an not relevant for coverage here - return from_stream(input, output); - // LCOV_EXCL_STOP -} - -/// Non-string parsable by a stream -template ::value == object_category::other && !std::is_assignable::value, - detail::enabler> = detail::dummy> -bool lexical_cast(const std::string &input, T &output) { - static_assert(is_istreamable::value, - "option object type must have a lexical cast overload or streaming input operator(>>) defined, if it " - "is convertible from another type use the add_option(...) with XC being the known type"); - return from_stream(input, output); -} - -/// Assign a value through lexical cast operations -/// Strings can be empty so we need to do a little different -template ::value && - (classify_object::value == object_category::string_assignable || - classify_object::value == object_category::string_constructible || - classify_object::value == object_category::wstring_assignable || - classify_object::value == object_category::wstring_constructible), - detail::enabler> = detail::dummy> -bool lexical_assign(const std::string &input, AssignTo &output) { - return lexical_cast(input, output); -} - -/// Assign a value through lexical cast operations -template ::value && std::is_assignable::value && - classify_object::value != object_category::string_assignable && - classify_object::value != object_category::string_constructible && - classify_object::value != object_category::wstring_assignable && - classify_object::value != object_category::wstring_constructible, - detail::enabler> = detail::dummy> -bool lexical_assign(const std::string &input, AssignTo &output) { - if(input.empty()) { - output = AssignTo{}; - return true; - } - - return lexical_cast(input, output); -} - -/// Assign a value through lexical cast operations -template ::value && !std::is_assignable::value && - classify_object::value == object_category::wrapper_value, - detail::enabler> = detail::dummy> -bool lexical_assign(const std::string &input, AssignTo &output) { - if(input.empty()) { - typename AssignTo::value_type emptyVal{}; - output = emptyVal; - return true; - } - return lexical_cast(input, output); -} - -/// Assign a value through lexical cast operations for int compatible values -/// mainly for atomic operations on some compilers -template ::value && !std::is_assignable::value && - classify_object::value != object_category::wrapper_value && - std::is_assignable::value, - detail::enabler> = detail::dummy> -bool lexical_assign(const std::string &input, AssignTo &output) { - if(input.empty()) { - output = 0; - return true; - } - int val{0}; - if(lexical_cast(input, val)) { -#if defined(__clang__) -/* on some older clang compilers */ -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wsign-conversion" -#endif - output = val; -#if defined(__clang__) -#pragma clang diagnostic pop -#endif - return true; - } - return false; -} - -/// Assign a value converted from a string in lexical cast to the output value directly -template ::value && std::is_assignable::value, - detail::enabler> = detail::dummy> -bool lexical_assign(const std::string &input, AssignTo &output) { - ConvertTo val{}; - bool parse_result = (!input.empty()) ? lexical_cast(input, val) : true; - if(parse_result) { - output = val; - } - return parse_result; -} - -/// Assign a value from a lexical cast through constructing a value and move assigning it -template < - typename AssignTo, - typename ConvertTo, - enable_if_t::value && !std::is_assignable::value && - std::is_move_assignable::value, - detail::enabler> = detail::dummy> -bool lexical_assign(const std::string &input, AssignTo &output) { - ConvertTo val{}; - bool parse_result = input.empty() ? true : lexical_cast(input, val); - if(parse_result) { - output = AssignTo(val); // use () form of constructor to allow some implicit conversions - } - return parse_result; -} - -/// primary lexical conversion operation, 1 string to 1 type of some kind -template ::value <= object_category::other && - classify_object::value <= object_category::wrapper_value, - detail::enabler> = detail::dummy> -bool lexical_conversion(const std::vector &strings, AssignTo &output) { - return lexical_assign(strings[0], output); -} - -/// Lexical conversion if there is only one element but the conversion type is for two, then call a two element -/// constructor -template ::value <= 2) && expected_count::value == 1 && - is_tuple_like::value && type_count_base::value == 2, - detail::enabler> = detail::dummy> -bool lexical_conversion(const std::vector &strings, AssignTo &output) { - // the remove const is to handle pair types coming from a container - using FirstType = typename std::remove_const::type>::type; - using SecondType = typename std::tuple_element<1, ConvertTo>::type; - FirstType v1; - SecondType v2; - bool retval = lexical_assign(strings[0], v1); - retval = retval && lexical_assign((strings.size() > 1) ? strings[1] : std::string{}, v2); - if(retval) { - output = AssignTo{v1, v2}; - } - return retval; -} - -/// Lexical conversion of a container types of single elements -template ::value && is_mutable_container::value && - type_count::value == 1, - detail::enabler> = detail::dummy> -bool lexical_conversion(const std::vector &strings, AssignTo &output) { - output.erase(output.begin(), output.end()); - if(strings.empty()) { - return true; - } - if(strings.size() == 1 && strings[0] == "{}") { - return true; - } - bool skip_remaining = false; - if(strings.size() == 2 && strings[0] == "{}" && is_separator(strings[1])) { - skip_remaining = true; - } - for(const auto &elem : strings) { - typename AssignTo::value_type out; - bool retval = lexical_assign(elem, out); - if(!retval) { - return false; - } - output.insert(output.end(), std::move(out)); - if(skip_remaining) { - break; - } - } - return (!output.empty()); -} - -/// Lexical conversion for complex types -template ::value, detail::enabler> = detail::dummy> -bool lexical_conversion(const std::vector &strings, AssignTo &output) { - - if(strings.size() >= 2 && !strings[1].empty()) { - using XC2 = typename wrapped_type::type; - XC2 x{0.0}, y{0.0}; - auto str1 = strings[1]; - if(str1.back() == 'i' || str1.back() == 'j') { - str1.pop_back(); - } - auto worked = lexical_cast(strings[0], x) && lexical_cast(str1, y); - if(worked) { - output = ConvertTo{x, y}; - } - return worked; - } - return lexical_assign(strings[0], output); -} - -/// Conversion to a vector type using a particular single type as the conversion type -template ::value && (expected_count::value == 1) && - (type_count::value == 1), - detail::enabler> = detail::dummy> -bool lexical_conversion(const std::vector &strings, AssignTo &output) { - bool retval = true; - output.clear(); - output.reserve(strings.size()); - for(const auto &elem : strings) { - - output.emplace_back(); - retval = retval && lexical_assign(elem, output.back()); - } - return (!output.empty()) && retval; -} - -// forward declaration - -/// Lexical conversion of a container types with conversion type of two elements -template ::value && is_mutable_container::value && - type_count_base::value == 2, - detail::enabler> = detail::dummy> -bool lexical_conversion(std::vector strings, AssignTo &output); - -/// Lexical conversion of a vector types with type_size >2 forward declaration -template ::value && is_mutable_container::value && - type_count_base::value != 2 && - ((type_count::value > 2) || - (type_count::value > type_count_base::value)), - detail::enabler> = detail::dummy> -bool lexical_conversion(const std::vector &strings, AssignTo &output); - -/// Conversion for tuples -template ::value && is_tuple_like::value && - (type_count_base::value != type_count::value || - type_count::value > 2), - detail::enabler> = detail::dummy> -bool lexical_conversion(const std::vector &strings, AssignTo &output); // forward declaration - -/// Conversion for operations where the assigned type is some class but the conversion is a mutable container or large -/// tuple -template ::value && !is_mutable_container::value && - classify_object::value != object_category::wrapper_value && - (is_mutable_container::value || type_count::value > 2), - detail::enabler> = detail::dummy> -bool lexical_conversion(const std::vector &strings, AssignTo &output) { - - if(strings.size() > 1 || (!strings.empty() && !(strings.front().empty()))) { - ConvertTo val; - auto retval = lexical_conversion(strings, val); - output = AssignTo{val}; - return retval; - } - output = AssignTo{}; - return true; -} - -/// function template for converting tuples if the static Index is greater than the tuple size -template -inline typename std::enable_if<(I >= type_count_base::value), bool>::type -tuple_conversion(const std::vector &, AssignTo &) { - return true; -} - -/// Conversion of a tuple element where the type size ==1 and not a mutable container -template -inline typename std::enable_if::value && type_count::value == 1, bool>::type -tuple_type_conversion(std::vector &strings, AssignTo &output) { - auto retval = lexical_assign(strings[0], output); - strings.erase(strings.begin()); - return retval; -} - -/// Conversion of a tuple element where the type size !=1 but the size is fixed and not a mutable container -template -inline typename std::enable_if::value && (type_count::value > 1) && - type_count::value == type_count_min::value, - bool>::type -tuple_type_conversion(std::vector &strings, AssignTo &output) { - auto retval = lexical_conversion(strings, output); - strings.erase(strings.begin(), strings.begin() + type_count::value); - return retval; -} - -/// Conversion of a tuple element where the type is a mutable container or a type with different min and max type sizes -template -inline typename std::enable_if::value || - type_count::value != type_count_min::value, - bool>::type -tuple_type_conversion(std::vector &strings, AssignTo &output) { - - std::size_t index{subtype_count_min::value}; - const std::size_t mx_count{subtype_count::value}; - const std::size_t mx{(std::min)(mx_count, strings.size() - 1)}; - - while(index < mx) { - if(is_separator(strings[index])) { - break; - } - ++index; - } - bool retval = lexical_conversion( - std::vector(strings.begin(), strings.begin() + static_cast(index)), output); - if(strings.size() > index) { - strings.erase(strings.begin(), strings.begin() + static_cast(index) + 1); - } else { - strings.clear(); - } - return retval; -} - -/// Tuple conversion operation -template -inline typename std::enable_if<(I < type_count_base::value), bool>::type -tuple_conversion(std::vector strings, AssignTo &output) { - bool retval = true; - using ConvertToElement = typename std:: - conditional::value, typename std::tuple_element::type, ConvertTo>::type; - if(!strings.empty()) { - retval = retval && tuple_type_conversion::type, ConvertToElement>( - strings, std::get(output)); - } - retval = retval && tuple_conversion(std::move(strings), output); - return retval; -} - -/// Lexical conversion of a container types with tuple elements of size 2 -template ::value && is_mutable_container::value && - type_count_base::value == 2, - detail::enabler>> -bool lexical_conversion(std::vector strings, AssignTo &output) { - output.clear(); - while(!strings.empty()) { - - typename std::remove_const::type>::type v1; - typename std::tuple_element<1, typename ConvertTo::value_type>::type v2; - bool retval = tuple_type_conversion(strings, v1); - if(!strings.empty()) { - retval = retval && tuple_type_conversion(strings, v2); - } - if(retval) { - output.insert(output.end(), typename AssignTo::value_type{v1, v2}); - } else { - return false; - } - } - return (!output.empty()); -} - -/// lexical conversion of tuples with type count>2 or tuples of types of some element with a type size>=2 -template ::value && is_tuple_like::value && - (type_count_base::value != type_count::value || - type_count::value > 2), - detail::enabler>> -bool lexical_conversion(const std::vector &strings, AssignTo &output) { - static_assert( - !is_tuple_like::value || type_count_base::value == type_count_base::value, - "if the conversion type is defined as a tuple it must be the same size as the type you are converting to"); - return tuple_conversion(strings, output); -} - -/// Lexical conversion of a vector types for everything but tuples of two elements and types of size 1 -template ::value && is_mutable_container::value && - type_count_base::value != 2 && - ((type_count::value > 2) || - (type_count::value > type_count_base::value)), - detail::enabler>> -bool lexical_conversion(const std::vector &strings, AssignTo &output) { - bool retval = true; - output.clear(); - std::vector temp; - std::size_t ii{0}; - std::size_t icount{0}; - std::size_t xcm{type_count::value}; - auto ii_max = strings.size(); - while(ii < ii_max) { - temp.push_back(strings[ii]); - ++ii; - ++icount; - if(icount == xcm || is_separator(temp.back()) || ii == ii_max) { - if(static_cast(xcm) > type_count_min::value && is_separator(temp.back())) { - temp.pop_back(); - } - typename AssignTo::value_type temp_out; - retval = retval && - lexical_conversion(temp, temp_out); - temp.clear(); - if(!retval) { - return false; - } - output.insert(output.end(), std::move(temp_out)); - icount = 0; - } - } - return retval; -} - -/// conversion for wrapper types -template ::value == object_category::wrapper_value && - std::is_assignable::value, - detail::enabler> = detail::dummy> -bool lexical_conversion(const std::vector &strings, AssignTo &output) { - if(strings.empty() || strings.front().empty()) { - output = ConvertTo{}; - return true; - } - typename ConvertTo::value_type val; - if(lexical_conversion(strings, val)) { - output = ConvertTo{val}; - return true; - } - return false; -} - -/// conversion for wrapper types -template ::value == object_category::wrapper_value && - !std::is_assignable::value, - detail::enabler> = detail::dummy> -bool lexical_conversion(const std::vector &strings, AssignTo &output) { - using ConvertType = typename ConvertTo::value_type; - if(strings.empty() || strings.front().empty()) { - output = ConvertType{}; - return true; - } - ConvertType val; - if(lexical_conversion(strings, val)) { - output = val; - return true; - } - return false; -} - -/// Sum a vector of strings -inline std::string sum_string_vector(const std::vector &values) { - double val{0.0}; - bool fail{false}; - std::string output; - for(const auto &arg : values) { - double tv{0.0}; - auto comp = lexical_cast(arg, tv); - if(!comp) { - errno = 0; - auto fv = detail::to_flag_value(arg); - fail = (errno != 0); - if(fail) { - break; - } - tv = static_cast(fv); - } - val += tv; - } - if(fail) { - for(const auto &arg : values) { - output.append(arg); - } - } else { - std::ostringstream out; - out.precision(16); - out << val; - output = out.str(); - } - return output; -} - -} // namespace detail - - - -namespace detail { - -// Returns false if not a short option. Otherwise, sets opt name and rest and returns true -CLI11_INLINE bool split_short(const std::string ¤t, std::string &name, std::string &rest); - -// Returns false if not a long option. Otherwise, sets opt name and other side of = and returns true -CLI11_INLINE bool split_long(const std::string ¤t, std::string &name, std::string &value); - -// Returns false if not a windows style option. Otherwise, sets opt name and value and returns true -CLI11_INLINE bool split_windows_style(const std::string ¤t, std::string &name, std::string &value); - -// Splits a string into multiple long and short names -CLI11_INLINE std::vector split_names(std::string current); - -/// extract default flag values either {def} or starting with a ! -CLI11_INLINE std::vector> get_default_flag_values(const std::string &str); - -/// Get a vector of short names, one of long names, and a single name -CLI11_INLINE std::tuple, std::vector, std::string> -get_names(const std::vector &input); - -} // namespace detail - - - -namespace detail { - -CLI11_INLINE bool split_short(const std::string ¤t, std::string &name, std::string &rest) { - if(current.size() > 1 && current[0] == '-' && valid_first_char(current[1])) { - name = current.substr(1, 1); - rest = current.substr(2); - return true; - } - return false; -} - -CLI11_INLINE bool split_long(const std::string ¤t, std::string &name, std::string &value) { - if(current.size() > 2 && current.compare(0, 2, "--") == 0 && valid_first_char(current[2])) { - auto loc = current.find_first_of('='); - if(loc != std::string::npos) { - name = current.substr(2, loc - 2); - value = current.substr(loc + 1); - } else { - name = current.substr(2); - value = ""; - } - return true; - } - return false; -} - -CLI11_INLINE bool split_windows_style(const std::string ¤t, std::string &name, std::string &value) { - if(current.size() > 1 && current[0] == '/' && valid_first_char(current[1])) { - auto loc = current.find_first_of(':'); - if(loc != std::string::npos) { - name = current.substr(1, loc - 1); - value = current.substr(loc + 1); - } else { - name = current.substr(1); - value = ""; - } - return true; - } - return false; -} - -CLI11_INLINE std::vector split_names(std::string current) { - std::vector output; - std::size_t val = 0; - while((val = current.find(',')) != std::string::npos) { - output.push_back(trim_copy(current.substr(0, val))); - current = current.substr(val + 1); - } - output.push_back(trim_copy(current)); - return output; -} - -CLI11_INLINE std::vector> get_default_flag_values(const std::string &str) { - std::vector flags = split_names(str); - flags.erase(std::remove_if(flags.begin(), - flags.end(), - [](const std::string &name) { - return ((name.empty()) || (!(((name.find_first_of('{') != std::string::npos) && - (name.back() == '}')) || - (name[0] == '!')))); - }), - flags.end()); - std::vector> output; - output.reserve(flags.size()); - for(auto &flag : flags) { - auto def_start = flag.find_first_of('{'); - std::string defval = "false"; - if((def_start != std::string::npos) && (flag.back() == '}')) { - defval = flag.substr(def_start + 1); - defval.pop_back(); - flag.erase(def_start, std::string::npos); // NOLINT(readability-suspicious-call-argument) - } - flag.erase(0, flag.find_first_not_of("-!")); - output.emplace_back(flag, defval); - } - return output; -} - -CLI11_INLINE std::tuple, std::vector, std::string> -get_names(const std::vector &input) { - - std::vector short_names; - std::vector long_names; - std::string pos_name; - for(std::string name : input) { - if(name.length() == 0) { - continue; - } - if(name.length() > 1 && name[0] == '-' && name[1] != '-') { - if(name.length() == 2 && valid_first_char(name[1])) - short_names.emplace_back(1, name[1]); - else if(name.length() > 2) - throw BadNameString::MissingDash(name); - else - throw BadNameString::OneCharName(name); - } else if(name.length() > 2 && name.substr(0, 2) == "--") { - name = name.substr(2); - if(valid_name_string(name)) - long_names.push_back(name); - else - throw BadNameString::BadLongName(name); - } else if(name == "-" || name == "--") { - throw BadNameString::DashesOnly(name); - } else { - if(!pos_name.empty()) - throw BadNameString::MultiPositionalNames(name); - if(valid_name_string(name)) { - pos_name = name; - } else { - throw BadNameString::BadPositionalName(name); - } - } - } - return std::make_tuple(short_names, long_names, pos_name); -} - -} // namespace detail - - - -class App; - -/// Holds values to load into Options -struct ConfigItem { - /// This is the list of parents - std::vector parents{}; - - /// This is the name - std::string name{}; - /// Listing of inputs - std::vector inputs{}; - - /// The list of parents and name joined by "." - CLI11_NODISCARD std::string fullname() const { - std::vector tmp = parents; - tmp.emplace_back(name); - return detail::join(tmp, "."); - } -}; - -/// This class provides a converter for configuration files. -class Config { - protected: - std::vector items{}; - - public: - /// Convert an app into a configuration - virtual std::string to_config(const App *, bool, bool, std::string) const = 0; - - /// Convert a configuration into an app - virtual std::vector from_config(std::istream &) const = 0; - - /// Get a flag value - CLI11_NODISCARD virtual std::string to_flag(const ConfigItem &item) const { - if(item.inputs.size() == 1) { - return item.inputs.at(0); - } - if(item.inputs.empty()) { - return "{}"; - } - throw ConversionError::TooManyInputsFlag(item.fullname()); // LCOV_EXCL_LINE - } - - /// Parse a config file, throw an error (ParseError:ConfigParseError or FileError) on failure - CLI11_NODISCARD std::vector from_file(const std::string &name) const { - std::ifstream input{name}; - if(!input.good()) - throw FileError::Missing(name); - - return from_config(input); - } - - /// Virtual destructor - virtual ~Config() = default; -}; - -/// This converter works with INI/TOML files; to write INI files use ConfigINI -class ConfigBase : public Config { - protected: - /// the character used for comments - char commentChar = '#'; - /// the character used to start an array '\0' is a default to not use - char arrayStart = '['; - /// the character used to end an array '\0' is a default to not use - char arrayEnd = ']'; - /// the character used to separate elements in an array - char arraySeparator = ','; - /// the character used separate the name from the value - char valueDelimiter = '='; - /// the character to use around strings - char stringQuote = '"'; - /// the character to use around single characters and literal strings - char literalQuote = '\''; - /// the maximum number of layers to allow - uint8_t maximumLayers{255}; - /// the separator used to separator parent layers - char parentSeparatorChar{'.'}; - /// Specify the configuration index to use for arrayed sections - int16_t configIndex{-1}; - /// Specify the configuration section that should be used - std::string configSection{}; - - public: - std::string - to_config(const App * /*app*/, bool default_also, bool write_description, std::string prefix) const override; - - std::vector from_config(std::istream &input) const override; - /// Specify the configuration for comment characters - ConfigBase *comment(char cchar) { - commentChar = cchar; - return this; - } - /// Specify the start and end characters for an array - ConfigBase *arrayBounds(char aStart, char aEnd) { - arrayStart = aStart; - arrayEnd = aEnd; - return this; - } - /// Specify the delimiter character for an array - ConfigBase *arrayDelimiter(char aSep) { - arraySeparator = aSep; - return this; - } - /// Specify the delimiter between a name and value - ConfigBase *valueSeparator(char vSep) { - valueDelimiter = vSep; - return this; - } - /// Specify the quote characters used around strings and literal strings - ConfigBase *quoteCharacter(char qString, char literalChar) { - stringQuote = qString; - literalQuote = literalChar; - return this; - } - /// Specify the maximum number of parents - ConfigBase *maxLayers(uint8_t layers) { - maximumLayers = layers; - return this; - } - /// Specify the separator to use for parent layers - ConfigBase *parentSeparator(char sep) { - parentSeparatorChar = sep; - return this; - } - /// get a reference to the configuration section - std::string §ionRef() { return configSection; } - /// get the section - CLI11_NODISCARD const std::string §ion() const { return configSection; } - /// specify a particular section of the configuration file to use - ConfigBase *section(const std::string §ionName) { - configSection = sectionName; - return this; - } - - /// get a reference to the configuration index - int16_t &indexRef() { return configIndex; } - /// get the section index - CLI11_NODISCARD int16_t index() const { return configIndex; } - /// specify a particular index in the section to use (-1) for all sections to use - ConfigBase *index(int16_t sectionIndex) { - configIndex = sectionIndex; - return this; - } -}; - -/// the default Config is the TOML file format -using ConfigTOML = ConfigBase; - -/// ConfigINI generates a "standard" INI compliant output -class ConfigINI : public ConfigTOML { - - public: - ConfigINI() { - commentChar = ';'; - arrayStart = '\0'; - arrayEnd = '\0'; - arraySeparator = ' '; - valueDelimiter = '='; - } -}; - - - -class Option; - -/// @defgroup validator_group Validators - -/// @brief Some validators that are provided -/// -/// These are simple `std::string(const std::string&)` validators that are useful. They return -/// a string if the validation fails. A custom struct is provided, as well, with the same user -/// semantics, but with the ability to provide a new type name. -/// @{ - -/// -class Validator { - protected: - /// This is the description function, if empty the description_ will be used - std::function desc_function_{[]() { return std::string{}; }}; - - /// This is the base function that is to be called. - /// Returns a string error message if validation fails. - std::function func_{[](std::string &) { return std::string{}; }}; - /// The name for search purposes of the Validator - std::string name_{}; - /// A Validator will only apply to an indexed value (-1 is all elements) - int application_index_ = -1; - /// Enable for Validator to allow it to be disabled if need be - bool active_{true}; - /// specify that a validator should not modify the input - bool non_modifying_{false}; - - Validator(std::string validator_desc, std::function func) - : desc_function_([validator_desc]() { return validator_desc; }), func_(std::move(func)) {} - - public: - Validator() = default; - /// Construct a Validator with just the description string - explicit Validator(std::string validator_desc) : desc_function_([validator_desc]() { return validator_desc; }) {} - /// Construct Validator from basic information - Validator(std::function op, std::string validator_desc, std::string validator_name = "") - : desc_function_([validator_desc]() { return validator_desc; }), func_(std::move(op)), - name_(std::move(validator_name)) {} - /// Set the Validator operation function - Validator &operation(std::function op) { - func_ = std::move(op); - return *this; - } - /// This is the required operator for a Validator - provided to help - /// users (CLI11 uses the member `func` directly) - std::string operator()(std::string &str) const; - - /// This is the required operator for a Validator - provided to help - /// users (CLI11 uses the member `func` directly) - std::string operator()(const std::string &str) const { - std::string value = str; - return (active_) ? func_(value) : std::string{}; - } - - /// Specify the type string - Validator &description(std::string validator_desc) { - desc_function_ = [validator_desc]() { return validator_desc; }; - return *this; - } - /// Specify the type string - CLI11_NODISCARD Validator description(std::string validator_desc) const; - - /// Generate type description information for the Validator - CLI11_NODISCARD std::string get_description() const { - if(active_) { - return desc_function_(); - } - return std::string{}; - } - /// Specify the type string - Validator &name(std::string validator_name) { - name_ = std::move(validator_name); - return *this; - } - /// Specify the type string - CLI11_NODISCARD Validator name(std::string validator_name) const { - Validator newval(*this); - newval.name_ = std::move(validator_name); - return newval; - } - /// Get the name of the Validator - CLI11_NODISCARD const std::string &get_name() const { return name_; } - /// Specify whether the Validator is active or not - Validator &active(bool active_val = true) { - active_ = active_val; - return *this; - } - /// Specify whether the Validator is active or not - CLI11_NODISCARD Validator active(bool active_val = true) const { - Validator newval(*this); - newval.active_ = active_val; - return newval; - } - - /// Specify whether the Validator can be modifying or not - Validator &non_modifying(bool no_modify = true) { - non_modifying_ = no_modify; - return *this; - } - /// Specify the application index of a validator - Validator &application_index(int app_index) { - application_index_ = app_index; - return *this; - } - /// Specify the application index of a validator - CLI11_NODISCARD Validator application_index(int app_index) const { - Validator newval(*this); - newval.application_index_ = app_index; - return newval; - } - /// Get the current value of the application index - CLI11_NODISCARD int get_application_index() const { return application_index_; } - /// Get a boolean if the validator is active - CLI11_NODISCARD bool get_active() const { return active_; } - - /// Get a boolean if the validator is allowed to modify the input returns true if it can modify the input - CLI11_NODISCARD bool get_modifying() const { return !non_modifying_; } - - /// Combining validators is a new validator. Type comes from left validator if function, otherwise only set if the - /// same. - Validator operator&(const Validator &other) const; - - /// Combining validators is a new validator. Type comes from left validator if function, otherwise only set if the - /// same. - Validator operator|(const Validator &other) const; - - /// Create a validator that fails when a given validator succeeds - Validator operator!() const; - - private: - void _merge_description(const Validator &val1, const Validator &val2, const std::string &merger); -}; - -/// Class wrapping some of the accessors of Validator -class CustomValidator : public Validator { - public: -}; -// The implementation of the built in validators is using the Validator class; -// the user is only expected to use the const (static) versions (since there's no setup). -// Therefore, this is in detail. -namespace detail { - -/// CLI enumeration of different file types -enum class path_type { nonexistent, file, directory }; - -/// get the type of the path from a file name -CLI11_INLINE path_type check_path(const char *file) noexcept; - -/// Check for an existing file (returns error message if check fails) -class ExistingFileValidator : public Validator { - public: - ExistingFileValidator(); -}; - -/// Check for an existing directory (returns error message if check fails) -class ExistingDirectoryValidator : public Validator { - public: - ExistingDirectoryValidator(); -}; - -/// Check for an existing path -class ExistingPathValidator : public Validator { - public: - ExistingPathValidator(); -}; - -/// Check for an non-existing path -class NonexistentPathValidator : public Validator { - public: - NonexistentPathValidator(); -}; - -/// Validate the given string is a legal ipv4 address -class IPV4Validator : public Validator { - public: - IPV4Validator(); -}; - -class EscapedStringTransformer : public Validator { - public: - EscapedStringTransformer(); -}; - -} // namespace detail - -// Static is not needed here, because global const implies static. - -/// Check for existing file (returns error message if check fails) -const detail::ExistingFileValidator ExistingFile; - -/// Check for an existing directory (returns error message if check fails) -const detail::ExistingDirectoryValidator ExistingDirectory; - -/// Check for an existing path -const detail::ExistingPathValidator ExistingPath; - -/// Check for an non-existing path -const detail::NonexistentPathValidator NonexistentPath; - -/// Check for an IP4 address -const detail::IPV4Validator ValidIPV4; - -/// convert escaped characters into their associated values -const detail::EscapedStringTransformer EscapedString; - -/// Validate the input as a particular type -template class TypeValidator : public Validator { - public: - explicit TypeValidator(const std::string &validator_name) - : Validator(validator_name, [](std::string &input_string) { - using CLI::detail::lexical_cast; - auto val = DesiredType(); - if(!lexical_cast(input_string, val)) { - return std::string("Failed parsing ") + input_string + " as a " + detail::type_name(); - } - return std::string(); - }) {} - TypeValidator() : TypeValidator(detail::type_name()) {} -}; - -/// Check for a number -const TypeValidator Number("NUMBER"); - -/// Modify a path if the file is a particular default location, can be used as Check or transform -/// with the error return optionally disabled -class FileOnDefaultPath : public Validator { - public: - explicit FileOnDefaultPath(std::string default_path, bool enableErrorReturn = true); -}; - -/// Produce a range (factory). Min and max are inclusive. -class Range : public Validator { - public: - /// This produces a range with min and max inclusive. - /// - /// Note that the constructor is templated, but the struct is not, so C++17 is not - /// needed to provide nice syntax for Range(a,b). - template - Range(T min_val, T max_val, const std::string &validator_name = std::string{}) : Validator(validator_name) { - if(validator_name.empty()) { - std::stringstream out; - out << detail::type_name() << " in [" << min_val << " - " << max_val << "]"; - description(out.str()); - } - - func_ = [min_val, max_val](std::string &input) { - using CLI::detail::lexical_cast; - T val; - bool converted = lexical_cast(input, val); - if((!converted) || (val < min_val || val > max_val)) { - std::stringstream out; - out << "Value " << input << " not in range ["; - out << min_val << " - " << max_val << "]"; - return out.str(); - } - return std::string{}; - }; - } - - /// Range of one value is 0 to value - template - explicit Range(T max_val, const std::string &validator_name = std::string{}) - : Range(static_cast(0), max_val, validator_name) {} -}; - -/// Check for a non negative number -const Range NonNegativeNumber((std::numeric_limits::max)(), "NONNEGATIVE"); - -/// Check for a positive valued number (val>0.0), ::min here is the smallest positive number -const Range PositiveNumber((std::numeric_limits::min)(), (std::numeric_limits::max)(), "POSITIVE"); - -/// Produce a bounded range (factory). Min and max are inclusive. -class Bound : public Validator { - public: - /// This bounds a value with min and max inclusive. - /// - /// Note that the constructor is templated, but the struct is not, so C++17 is not - /// needed to provide nice syntax for Range(a,b). - template Bound(T min_val, T max_val) { - std::stringstream out; - out << detail::type_name() << " bounded to [" << min_val << " - " << max_val << "]"; - description(out.str()); - - func_ = [min_val, max_val](std::string &input) { - using CLI::detail::lexical_cast; - T val; - bool converted = lexical_cast(input, val); - if(!converted) { - return std::string("Value ") + input + " could not be converted"; - } - if(val < min_val) - input = detail::to_string(min_val); - else if(val > max_val) - input = detail::to_string(max_val); - - return std::string{}; - }; - } - - /// Range of one value is 0 to value - template explicit Bound(T max_val) : Bound(static_cast(0), max_val) {} -}; - -namespace detail { -template ::type>::value, detail::enabler> = detail::dummy> -auto smart_deref(T value) -> decltype(*value) { - return *value; -} - -template < - typename T, - enable_if_t::type>::value, detail::enabler> = detail::dummy> -typename std::remove_reference::type &smart_deref(T &value) { - return value; -} -/// Generate a string representation of a set -template std::string generate_set(const T &set) { - using element_t = typename detail::element_type::type; - using iteration_type_t = typename detail::pair_adaptor::value_type; // the type of the object pair - std::string out(1, '{'); - out.append(detail::join( - detail::smart_deref(set), - [](const iteration_type_t &v) { return detail::pair_adaptor::first(v); }, - ",")); - out.push_back('}'); - return out; -} - -/// Generate a string representation of a map -template std::string generate_map(const T &map, bool key_only = false) { - using element_t = typename detail::element_type::type; - using iteration_type_t = typename detail::pair_adaptor::value_type; // the type of the object pair - std::string out(1, '{'); - out.append(detail::join( - detail::smart_deref(map), - [key_only](const iteration_type_t &v) { - std::string res{detail::to_string(detail::pair_adaptor::first(v))}; - - if(!key_only) { - res.append("->"); - res += detail::to_string(detail::pair_adaptor::second(v)); - } - return res; - }, - ",")); - out.push_back('}'); - return out; -} - -template struct has_find { - template - static auto test(int) -> decltype(std::declval().find(std::declval()), std::true_type()); - template static auto test(...) -> decltype(std::false_type()); - - static const auto value = decltype(test(0))::value; - using type = std::integral_constant; -}; - -/// A search function -template ::value, detail::enabler> = detail::dummy> -auto search(const T &set, const V &val) -> std::pair { - using element_t = typename detail::element_type::type; - auto &setref = detail::smart_deref(set); - auto it = std::find_if(std::begin(setref), std::end(setref), [&val](decltype(*std::begin(setref)) v) { - return (detail::pair_adaptor::first(v) == val); - }); - return {(it != std::end(setref)), it}; -} - -/// A search function that uses the built in find function -template ::value, detail::enabler> = detail::dummy> -auto search(const T &set, const V &val) -> std::pair { - auto &setref = detail::smart_deref(set); - auto it = setref.find(val); - return {(it != std::end(setref)), it}; -} - -/// A search function with a filter function -template -auto search(const T &set, const V &val, const std::function &filter_function) - -> std::pair { - using element_t = typename detail::element_type::type; - // do the potentially faster first search - auto res = search(set, val); - if((res.first) || (!(filter_function))) { - return res; - } - // if we haven't found it do the longer linear search with all the element translations - auto &setref = detail::smart_deref(set); - auto it = std::find_if(std::begin(setref), std::end(setref), [&](decltype(*std::begin(setref)) v) { - V a{detail::pair_adaptor::first(v)}; - a = filter_function(a); - return (a == val); - }); - return {(it != std::end(setref)), it}; -} - -// the following suggestion was made by Nikita Ofitserov(@himikof) -// done in templates to prevent compiler warnings on negation of unsigned numbers - -/// Do a check for overflow on signed numbers -template -inline typename std::enable_if::value, T>::type overflowCheck(const T &a, const T &b) { - if((a > 0) == (b > 0)) { - return ((std::numeric_limits::max)() / (std::abs)(a) < (std::abs)(b)); - } - return ((std::numeric_limits::min)() / (std::abs)(a) > -(std::abs)(b)); -} -/// Do a check for overflow on unsigned numbers -template -inline typename std::enable_if::value, T>::type overflowCheck(const T &a, const T &b) { - return ((std::numeric_limits::max)() / a < b); -} - -/// Performs a *= b; if it doesn't cause integer overflow. Returns false otherwise. -template typename std::enable_if::value, bool>::type checked_multiply(T &a, T b) { - if(a == 0 || b == 0 || a == 1 || b == 1) { - a *= b; - return true; - } - if(a == (std::numeric_limits::min)() || b == (std::numeric_limits::min)()) { - return false; - } - if(overflowCheck(a, b)) { - return false; - } - a *= b; - return true; -} - -/// Performs a *= b; if it doesn't equal infinity. Returns false otherwise. -template -typename std::enable_if::value, bool>::type checked_multiply(T &a, T b) { - T c = a * b; - if(std::isinf(c) && !std::isinf(a) && !std::isinf(b)) { - return false; - } - a = c; - return true; -} - -} // namespace detail -/// Verify items are in a set -class IsMember : public Validator { - public: - using filter_fn_t = std::function; - - /// This allows in-place construction using an initializer list - template - IsMember(std::initializer_list values, Args &&...args) - : IsMember(std::vector(values), std::forward(args)...) {} - - /// This checks to see if an item is in a set (empty function) - template explicit IsMember(T &&set) : IsMember(std::forward(set), nullptr) {} - - /// This checks to see if an item is in a set: pointer or copy version. You can pass in a function that will filter - /// both sides of the comparison before computing the comparison. - template explicit IsMember(T set, F filter_function) { - - // Get the type of the contained item - requires a container have ::value_type - // if the type does not have first_type and second_type, these are both value_type - using element_t = typename detail::element_type::type; // Removes (smart) pointers if needed - using item_t = typename detail::pair_adaptor::first_type; // Is value_type if not a map - - using local_item_t = typename IsMemberType::type; // This will convert bad types to good ones - // (const char * to std::string) - - // Make a local copy of the filter function, using a std::function if not one already - std::function filter_fn = filter_function; - - // This is the type name for help, it will take the current version of the set contents - desc_function_ = [set]() { return detail::generate_set(detail::smart_deref(set)); }; - - // This is the function that validates - // It stores a copy of the set pointer-like, so shared_ptr will stay alive - func_ = [set, filter_fn](std::string &input) { - using CLI::detail::lexical_cast; - local_item_t b; - if(!lexical_cast(input, b)) { - throw ValidationError(input); // name is added later - } - if(filter_fn) { - b = filter_fn(b); - } - auto res = detail::search(set, b, filter_fn); - if(res.first) { - // Make sure the version in the input string is identical to the one in the set - if(filter_fn) { - input = detail::value_string(detail::pair_adaptor::first(*(res.second))); - } - - // Return empty error string (success) - return std::string{}; - } - - // If you reach this point, the result was not found - return input + " not in " + detail::generate_set(detail::smart_deref(set)); - }; - } - - /// You can pass in as many filter functions as you like, they nest (string only currently) - template - IsMember(T &&set, filter_fn_t filter_fn_1, filter_fn_t filter_fn_2, Args &&...other) - : IsMember( - std::forward(set), - [filter_fn_1, filter_fn_2](std::string a) { return filter_fn_2(filter_fn_1(a)); }, - other...) {} -}; - -/// definition of the default transformation object -template using TransformPairs = std::vector>; - -/// Translate named items to other or a value set -class Transformer : public Validator { - public: - using filter_fn_t = std::function; - - /// This allows in-place construction - template - Transformer(std::initializer_list> values, Args &&...args) - : Transformer(TransformPairs(values), std::forward(args)...) {} - - /// direct map of std::string to std::string - template explicit Transformer(T &&mapping) : Transformer(std::forward(mapping), nullptr) {} - - /// This checks to see if an item is in a set: pointer or copy version. You can pass in a function that will filter - /// both sides of the comparison before computing the comparison. - template explicit Transformer(T mapping, F filter_function) { - - static_assert(detail::pair_adaptor::type>::value, - "mapping must produce value pairs"); - // Get the type of the contained item - requires a container have ::value_type - // if the type does not have first_type and second_type, these are both value_type - using element_t = typename detail::element_type::type; // Removes (smart) pointers if needed - using item_t = typename detail::pair_adaptor::first_type; // Is value_type if not a map - using local_item_t = typename IsMemberType::type; // Will convert bad types to good ones - // (const char * to std::string) - - // Make a local copy of the filter function, using a std::function if not one already - std::function filter_fn = filter_function; - - // This is the type name for help, it will take the current version of the set contents - desc_function_ = [mapping]() { return detail::generate_map(detail::smart_deref(mapping)); }; - - func_ = [mapping, filter_fn](std::string &input) { - using CLI::detail::lexical_cast; - local_item_t b; - if(!lexical_cast(input, b)) { - return std::string(); - // there is no possible way we can match anything in the mapping if we can't convert so just return - } - if(filter_fn) { - b = filter_fn(b); - } - auto res = detail::search(mapping, b, filter_fn); - if(res.first) { - input = detail::value_string(detail::pair_adaptor::second(*res.second)); - } - return std::string{}; - }; - } - - /// You can pass in as many filter functions as you like, they nest - template - Transformer(T &&mapping, filter_fn_t filter_fn_1, filter_fn_t filter_fn_2, Args &&...other) - : Transformer( - std::forward(mapping), - [filter_fn_1, filter_fn_2](std::string a) { return filter_fn_2(filter_fn_1(a)); }, - other...) {} -}; - -/// translate named items to other or a value set -class CheckedTransformer : public Validator { - public: - using filter_fn_t = std::function; - - /// This allows in-place construction - template - CheckedTransformer(std::initializer_list> values, Args &&...args) - : CheckedTransformer(TransformPairs(values), std::forward(args)...) {} - - /// direct map of std::string to std::string - template explicit CheckedTransformer(T mapping) : CheckedTransformer(std::move(mapping), nullptr) {} - - /// This checks to see if an item is in a set: pointer or copy version. You can pass in a function that will filter - /// both sides of the comparison before computing the comparison. - template explicit CheckedTransformer(T mapping, F filter_function) { - - static_assert(detail::pair_adaptor::type>::value, - "mapping must produce value pairs"); - // Get the type of the contained item - requires a container have ::value_type - // if the type does not have first_type and second_type, these are both value_type - using element_t = typename detail::element_type::type; // Removes (smart) pointers if needed - using item_t = typename detail::pair_adaptor::first_type; // Is value_type if not a map - using local_item_t = typename IsMemberType::type; // Will convert bad types to good ones - // (const char * to std::string) - using iteration_type_t = typename detail::pair_adaptor::value_type; // the type of the object pair - - // Make a local copy of the filter function, using a std::function if not one already - std::function filter_fn = filter_function; - - auto tfunc = [mapping]() { - std::string out("value in "); - out += detail::generate_map(detail::smart_deref(mapping)) + " OR {"; - out += detail::join( - detail::smart_deref(mapping), - [](const iteration_type_t &v) { return detail::to_string(detail::pair_adaptor::second(v)); }, - ","); - out.push_back('}'); - return out; - }; - - desc_function_ = tfunc; - - func_ = [mapping, tfunc, filter_fn](std::string &input) { - using CLI::detail::lexical_cast; - local_item_t b; - bool converted = lexical_cast(input, b); - if(converted) { - if(filter_fn) { - b = filter_fn(b); - } - auto res = detail::search(mapping, b, filter_fn); - if(res.first) { - input = detail::value_string(detail::pair_adaptor::second(*res.second)); - return std::string{}; - } - } - for(const auto &v : detail::smart_deref(mapping)) { - auto output_string = detail::value_string(detail::pair_adaptor::second(v)); - if(output_string == input) { - return std::string(); - } - } - - return "Check " + input + " " + tfunc() + " FAILED"; - }; - } - - /// You can pass in as many filter functions as you like, they nest - template - CheckedTransformer(T &&mapping, filter_fn_t filter_fn_1, filter_fn_t filter_fn_2, Args &&...other) - : CheckedTransformer( - std::forward(mapping), - [filter_fn_1, filter_fn_2](std::string a) { return filter_fn_2(filter_fn_1(a)); }, - other...) {} -}; - -/// Helper function to allow ignore_case to be passed to IsMember or Transform -inline std::string ignore_case(std::string item) { return detail::to_lower(item); } - -/// Helper function to allow ignore_underscore to be passed to IsMember or Transform -inline std::string ignore_underscore(std::string item) { return detail::remove_underscore(item); } - -/// Helper function to allow checks to ignore spaces to be passed to IsMember or Transform -inline std::string ignore_space(std::string item) { - item.erase(std::remove(std::begin(item), std::end(item), ' '), std::end(item)); - item.erase(std::remove(std::begin(item), std::end(item), '\t'), std::end(item)); - return item; -} - -/// Multiply a number by a factor using given mapping. -/// Can be used to write transforms for SIZE or DURATION inputs. -/// -/// Example: -/// With mapping = `{"b"->1, "kb"->1024, "mb"->1024*1024}` -/// one can recognize inputs like "100", "12kb", "100 MB", -/// that will be automatically transformed to 100, 14448, 104857600. -/// -/// Output number type matches the type in the provided mapping. -/// Therefore, if it is required to interpret real inputs like "0.42 s", -/// the mapping should be of a type or . -class AsNumberWithUnit : public Validator { - public: - /// Adjust AsNumberWithUnit behavior. - /// CASE_SENSITIVE/CASE_INSENSITIVE controls how units are matched. - /// UNIT_OPTIONAL/UNIT_REQUIRED throws ValidationError - /// if UNIT_REQUIRED is set and unit literal is not found. - enum Options { - CASE_SENSITIVE = 0, - CASE_INSENSITIVE = 1, - UNIT_OPTIONAL = 0, - UNIT_REQUIRED = 2, - DEFAULT = CASE_INSENSITIVE | UNIT_OPTIONAL - }; - - template - explicit AsNumberWithUnit(std::map mapping, - Options opts = DEFAULT, - const std::string &unit_name = "UNIT") { - description(generate_description(unit_name, opts)); - validate_mapping(mapping, opts); - - // transform function - func_ = [mapping, opts](std::string &input) -> std::string { - Number num{}; - - detail::rtrim(input); - if(input.empty()) { - throw ValidationError("Input is empty"); - } - - // Find split position between number and prefix - auto unit_begin = input.end(); - while(unit_begin > input.begin() && std::isalpha(*(unit_begin - 1), std::locale())) { - --unit_begin; - } - - std::string unit{unit_begin, input.end()}; - input.resize(static_cast(std::distance(input.begin(), unit_begin))); - detail::trim(input); - - if(opts & UNIT_REQUIRED && unit.empty()) { - throw ValidationError("Missing mandatory unit"); - } - if(opts & CASE_INSENSITIVE) { - unit = detail::to_lower(unit); - } - if(unit.empty()) { - using CLI::detail::lexical_cast; - if(!lexical_cast(input, num)) { - throw ValidationError(std::string("Value ") + input + " could not be converted to " + - detail::type_name()); - } - // No need to modify input if no unit passed - return {}; - } - - // find corresponding factor - auto it = mapping.find(unit); - if(it == mapping.end()) { - throw ValidationError(unit + - " unit not recognized. " - "Allowed values: " + - detail::generate_map(mapping, true)); - } - - if(!input.empty()) { - using CLI::detail::lexical_cast; - bool converted = lexical_cast(input, num); - if(!converted) { - throw ValidationError(std::string("Value ") + input + " could not be converted to " + - detail::type_name()); - } - // perform safe multiplication - bool ok = detail::checked_multiply(num, it->second); - if(!ok) { - throw ValidationError(detail::to_string(num) + " multiplied by " + unit + - " factor would cause number overflow. Use smaller value."); - } - } else { - num = static_cast(it->second); - } - - input = detail::to_string(num); - - return {}; - }; - } - - private: - /// Check that mapping contains valid units. - /// Update mapping for CASE_INSENSITIVE mode. - template static void validate_mapping(std::map &mapping, Options opts) { - for(auto &kv : mapping) { - if(kv.first.empty()) { - throw ValidationError("Unit must not be empty."); - } - if(!detail::isalpha(kv.first)) { - throw ValidationError("Unit must contain only letters."); - } - } - - // make all units lowercase if CASE_INSENSITIVE - if(opts & CASE_INSENSITIVE) { - std::map lower_mapping; - for(auto &kv : mapping) { - auto s = detail::to_lower(kv.first); - if(lower_mapping.count(s)) { - throw ValidationError(std::string("Several matching lowercase unit representations are found: ") + - s); - } - lower_mapping[detail::to_lower(kv.first)] = kv.second; - } - mapping = std::move(lower_mapping); - } - } - - /// Generate description like this: NUMBER [UNIT] - template static std::string generate_description(const std::string &name, Options opts) { - std::stringstream out; - out << detail::type_name() << ' '; - if(opts & UNIT_REQUIRED) { - out << name; - } else { - out << '[' << name << ']'; - } - return out.str(); - } -}; - -inline AsNumberWithUnit::Options operator|(const AsNumberWithUnit::Options &a, const AsNumberWithUnit::Options &b) { - return static_cast(static_cast(a) | static_cast(b)); -} - -/// Converts a human-readable size string (with unit literal) to uin64_t size. -/// Example: -/// "100" => 100 -/// "1 b" => 100 -/// "10Kb" => 10240 // you can configure this to be interpreted as kilobyte (*1000) or kibibyte (*1024) -/// "10 KB" => 10240 -/// "10 kb" => 10240 -/// "10 kib" => 10240 // *i, *ib are always interpreted as *bibyte (*1024) -/// "10kb" => 10240 -/// "2 MB" => 2097152 -/// "2 EiB" => 2^61 // Units up to exibyte are supported -class AsSizeValue : public AsNumberWithUnit { - public: - using result_t = std::uint64_t; - - /// If kb_is_1000 is true, - /// interpret 'kb', 'k' as 1000 and 'kib', 'ki' as 1024 - /// (same applies to higher order units as well). - /// Otherwise, interpret all literals as factors of 1024. - /// The first option is formally correct, but - /// the second interpretation is more wide-spread - /// (see https://en.wikipedia.org/wiki/Binary_prefix). - explicit AsSizeValue(bool kb_is_1000); - - private: - /// Get mapping - static std::map init_mapping(bool kb_is_1000); - - /// Cache calculated mapping - static std::map get_mapping(bool kb_is_1000); -}; - -namespace detail { -/// Split a string into a program name and command line arguments -/// the string is assumed to contain a file name followed by other arguments -/// the return value contains is a pair with the first argument containing the program name and the second -/// everything else. -CLI11_INLINE std::pair split_program_name(std::string commandline); - -} // namespace detail -/// @} - - - - -CLI11_INLINE std::string Validator::operator()(std::string &str) const { - std::string retstring; - if(active_) { - if(non_modifying_) { - std::string value = str; - retstring = func_(value); - } else { - retstring = func_(str); - } - } - return retstring; -} - -CLI11_NODISCARD CLI11_INLINE Validator Validator::description(std::string validator_desc) const { - Validator newval(*this); - newval.desc_function_ = [validator_desc]() { return validator_desc; }; - return newval; -} - -CLI11_INLINE Validator Validator::operator&(const Validator &other) const { - Validator newval; - - newval._merge_description(*this, other, " AND "); - - // Give references (will make a copy in lambda function) - const std::function &f1 = func_; - const std::function &f2 = other.func_; - - newval.func_ = [f1, f2](std::string &input) { - std::string s1 = f1(input); - std::string s2 = f2(input); - if(!s1.empty() && !s2.empty()) - return std::string("(") + s1 + ") AND (" + s2 + ")"; - return s1 + s2; - }; - - newval.active_ = active_ && other.active_; - newval.application_index_ = application_index_; - return newval; -} - -CLI11_INLINE Validator Validator::operator|(const Validator &other) const { - Validator newval; - - newval._merge_description(*this, other, " OR "); - - // Give references (will make a copy in lambda function) - const std::function &f1 = func_; - const std::function &f2 = other.func_; - - newval.func_ = [f1, f2](std::string &input) { - std::string s1 = f1(input); - std::string s2 = f2(input); - if(s1.empty() || s2.empty()) - return std::string(); - - return std::string("(") + s1 + ") OR (" + s2 + ")"; - }; - newval.active_ = active_ && other.active_; - newval.application_index_ = application_index_; - return newval; -} - -CLI11_INLINE Validator Validator::operator!() const { - Validator newval; - const std::function &dfunc1 = desc_function_; - newval.desc_function_ = [dfunc1]() { - auto str = dfunc1(); - return (!str.empty()) ? std::string("NOT ") + str : std::string{}; - }; - // Give references (will make a copy in lambda function) - const std::function &f1 = func_; - - newval.func_ = [f1, dfunc1](std::string &test) -> std::string { - std::string s1 = f1(test); - if(s1.empty()) { - return std::string("check ") + dfunc1() + " succeeded improperly"; - } - return std::string{}; - }; - newval.active_ = active_; - newval.application_index_ = application_index_; - return newval; -} - -CLI11_INLINE void -Validator::_merge_description(const Validator &val1, const Validator &val2, const std::string &merger) { - - const std::function &dfunc1 = val1.desc_function_; - const std::function &dfunc2 = val2.desc_function_; - - desc_function_ = [=]() { - std::string f1 = dfunc1(); - std::string f2 = dfunc2(); - if((f1.empty()) || (f2.empty())) { - return f1 + f2; - } - return std::string(1, '(') + f1 + ')' + merger + '(' + f2 + ')'; - }; -} - -namespace detail { - -#if defined CLI11_HAS_FILESYSTEM && CLI11_HAS_FILESYSTEM > 0 -CLI11_INLINE path_type check_path(const char *file) noexcept { - std::error_code ec; - auto stat = std::filesystem::status(to_path(file), ec); - if(ec) { - return path_type::nonexistent; - } - switch(stat.type()) { - case std::filesystem::file_type::none: // LCOV_EXCL_LINE - case std::filesystem::file_type::not_found: - return path_type::nonexistent; // LCOV_EXCL_LINE - case std::filesystem::file_type::directory: - return path_type::directory; - case std::filesystem::file_type::symlink: - case std::filesystem::file_type::block: - case std::filesystem::file_type::character: - case std::filesystem::file_type::fifo: - case std::filesystem::file_type::socket: - case std::filesystem::file_type::regular: - case std::filesystem::file_type::unknown: - default: - return path_type::file; - } -} -#else -CLI11_INLINE path_type check_path(const char *file) noexcept { -#if defined(_MSC_VER) - struct __stat64 buffer; - if(_stat64(file, &buffer) == 0) { - return ((buffer.st_mode & S_IFDIR) != 0) ? path_type::directory : path_type::file; - } -#else - struct stat buffer; - if(stat(file, &buffer) == 0) { - return ((buffer.st_mode & S_IFDIR) != 0) ? path_type::directory : path_type::file; - } -#endif - return path_type::nonexistent; -} -#endif - -CLI11_INLINE ExistingFileValidator::ExistingFileValidator() : Validator("FILE") { - func_ = [](std::string &filename) { - auto path_result = check_path(filename.c_str()); - if(path_result == path_type::nonexistent) { - return "File does not exist: " + filename; - } - if(path_result == path_type::directory) { - return "File is actually a directory: " + filename; - } - return std::string(); - }; -} - -CLI11_INLINE ExistingDirectoryValidator::ExistingDirectoryValidator() : Validator("DIR") { - func_ = [](std::string &filename) { - auto path_result = check_path(filename.c_str()); - if(path_result == path_type::nonexistent) { - return "Directory does not exist: " + filename; - } - if(path_result == path_type::file) { - return "Directory is actually a file: " + filename; - } - return std::string(); - }; -} - -CLI11_INLINE ExistingPathValidator::ExistingPathValidator() : Validator("PATH(existing)") { - func_ = [](std::string &filename) { - auto path_result = check_path(filename.c_str()); - if(path_result == path_type::nonexistent) { - return "Path does not exist: " + filename; - } - return std::string(); - }; -} - -CLI11_INLINE NonexistentPathValidator::NonexistentPathValidator() : Validator("PATH(non-existing)") { - func_ = [](std::string &filename) { - auto path_result = check_path(filename.c_str()); - if(path_result != path_type::nonexistent) { - return "Path already exists: " + filename; - } - return std::string(); - }; -} - -CLI11_INLINE IPV4Validator::IPV4Validator() : Validator("IPV4") { - func_ = [](std::string &ip_addr) { - auto result = CLI::detail::split(ip_addr, '.'); - if(result.size() != 4) { - return std::string("Invalid IPV4 address must have four parts (") + ip_addr + ')'; - } - int num = 0; - for(const auto &var : result) { - using CLI::detail::lexical_cast; - bool retval = lexical_cast(var, num); - if(!retval) { - return std::string("Failed parsing number (") + var + ')'; - } - if(num < 0 || num > 255) { - return std::string("Each IP number must be between 0 and 255 ") + var; - } - } - return std::string{}; - }; -} - -CLI11_INLINE EscapedStringTransformer::EscapedStringTransformer() { - func_ = [](std::string &str) { - try { - if(str.size() > 1 && (str.front() == '\"' || str.front() == '\'' || str.front() == '`') && - str.front() == str.back()) { - process_quoted_string(str); - } else if(str.find_first_of('\\') != std::string::npos) { - if(detail::is_binary_escaped_string(str)) { - str = detail::extract_binary_string(str); - } else { - str = remove_escaped_characters(str); - } - } - return std::string{}; - } catch(const std::invalid_argument &ia) { - return std::string(ia.what()); - } - }; -} -} // namespace detail - -CLI11_INLINE FileOnDefaultPath::FileOnDefaultPath(std::string default_path, bool enableErrorReturn) - : Validator("FILE") { - func_ = [default_path, enableErrorReturn](std::string &filename) { - auto path_result = detail::check_path(filename.c_str()); - if(path_result == detail::path_type::nonexistent) { - std::string test_file_path = default_path; - if(default_path.back() != '/' && default_path.back() != '\\') { - // Add folder separator - test_file_path += '/'; - } - test_file_path.append(filename); - path_result = detail::check_path(test_file_path.c_str()); - if(path_result == detail::path_type::file) { - filename = test_file_path; - } else { - if(enableErrorReturn) { - return "File does not exist: " + filename; - } - } - } - return std::string{}; - }; -} - -CLI11_INLINE AsSizeValue::AsSizeValue(bool kb_is_1000) : AsNumberWithUnit(get_mapping(kb_is_1000)) { - if(kb_is_1000) { - description("SIZE [b, kb(=1000b), kib(=1024b), ...]"); - } else { - description("SIZE [b, kb(=1024b), ...]"); - } -} - -CLI11_INLINE std::map AsSizeValue::init_mapping(bool kb_is_1000) { - std::map m; - result_t k_factor = kb_is_1000 ? 1000 : 1024; - result_t ki_factor = 1024; - result_t k = 1; - result_t ki = 1; - m["b"] = 1; - for(std::string p : {"k", "m", "g", "t", "p", "e"}) { - k *= k_factor; - ki *= ki_factor; - m[p] = k; - m[p + "b"] = k; - m[p + "i"] = ki; - m[p + "ib"] = ki; - } - return m; -} - -CLI11_INLINE std::map AsSizeValue::get_mapping(bool kb_is_1000) { - if(kb_is_1000) { - static auto m = init_mapping(true); - return m; - } - static auto m = init_mapping(false); - return m; -} - -namespace detail { - -CLI11_INLINE std::pair split_program_name(std::string commandline) { - // try to determine the programName - std::pair vals; - trim(commandline); - auto esp = commandline.find_first_of(' ', 1); - while(detail::check_path(commandline.substr(0, esp).c_str()) != path_type::file) { - esp = commandline.find_first_of(' ', esp + 1); - if(esp == std::string::npos) { - // if we have reached the end and haven't found a valid file just assume the first argument is the - // program name - if(commandline[0] == '"' || commandline[0] == '\'' || commandline[0] == '`') { - bool embeddedQuote = false; - auto keyChar = commandline[0]; - auto end = commandline.find_first_of(keyChar, 1); - while((end != std::string::npos) && (commandline[end - 1] == '\\')) { // deal with escaped quotes - end = commandline.find_first_of(keyChar, end + 1); - embeddedQuote = true; - } - if(end != std::string::npos) { - vals.first = commandline.substr(1, end - 1); - esp = end + 1; - if(embeddedQuote) { - vals.first = find_and_replace(vals.first, std::string("\\") + keyChar, std::string(1, keyChar)); - } - } else { - esp = commandline.find_first_of(' ', 1); - } - } else { - esp = commandline.find_first_of(' ', 1); - } - - break; - } - } - if(vals.first.empty()) { - vals.first = commandline.substr(0, esp); - rtrim(vals.first); - } - - // strip the program name - vals.second = (esp < commandline.length() - 1) ? commandline.substr(esp + 1) : std::string{}; - ltrim(vals.second); - return vals; -} - -} // namespace detail -/// @} - - - - -class Option; -class App; - -/// This enum signifies the type of help requested -/// -/// This is passed in by App; all user classes must accept this as -/// the second argument. - -enum class AppFormatMode { - Normal, ///< The normal, detailed help - All, ///< A fully expanded help - Sub, ///< Used when printed as part of expanded subcommand -}; - -/// This is the minimum requirements to run a formatter. -/// -/// A user can subclass this is if they do not care at all -/// about the structure in CLI::Formatter. -class FormatterBase { - protected: - /// @name Options - ///@{ - - /// The width of the first column - std::size_t column_width_{30}; - - /// @brief The required help printout labels (user changeable) - /// Values are Needs, Excludes, etc. - std::map labels_{}; - - ///@} - /// @name Basic - ///@{ - - public: - FormatterBase() = default; - FormatterBase(const FormatterBase &) = default; - FormatterBase(FormatterBase &&) = default; - FormatterBase &operator=(const FormatterBase &) = default; - FormatterBase &operator=(FormatterBase &&) = default; - - /// Adding a destructor in this form to work around bug in GCC 4.7 - virtual ~FormatterBase() noexcept {} // NOLINT(modernize-use-equals-default) - - /// This is the key method that puts together help - virtual std::string make_help(const App *, std::string, AppFormatMode) const = 0; - - ///@} - /// @name Setters - ///@{ - - /// Set the "REQUIRED" label - void label(std::string key, std::string val) { labels_[key] = val; } - - /// Set the column width - void column_width(std::size_t val) { column_width_ = val; } - - ///@} - /// @name Getters - ///@{ - - /// Get the current value of a name (REQUIRED, etc.) - CLI11_NODISCARD std::string get_label(std::string key) const { - if(labels_.find(key) == labels_.end()) - return key; - return labels_.at(key); - } - - /// Get the current column width - CLI11_NODISCARD std::size_t get_column_width() const { return column_width_; } - - ///@} -}; - -/// This is a specialty override for lambda functions -class FormatterLambda final : public FormatterBase { - using funct_t = std::function; - - /// The lambda to hold and run - funct_t lambda_; - - public: - /// Create a FormatterLambda with a lambda function - explicit FormatterLambda(funct_t funct) : lambda_(std::move(funct)) {} - - /// Adding a destructor (mostly to make GCC 4.7 happy) - ~FormatterLambda() noexcept override {} // NOLINT(modernize-use-equals-default) - - /// This will simply call the lambda function - std::string make_help(const App *app, std::string name, AppFormatMode mode) const override { - return lambda_(app, name, mode); - } -}; - -/// This is the default Formatter for CLI11. It pretty prints help output, and is broken into quite a few -/// overridable methods, to be highly customizable with minimal effort. -class Formatter : public FormatterBase { - public: - Formatter() = default; - Formatter(const Formatter &) = default; - Formatter(Formatter &&) = default; - Formatter &operator=(const Formatter &) = default; - Formatter &operator=(Formatter &&) = default; - - /// @name Overridables - ///@{ - - /// This prints out a group of options with title - /// - CLI11_NODISCARD virtual std::string - make_group(std::string group, bool is_positional, std::vector opts) const; - - /// This prints out just the positionals "group" - virtual std::string make_positionals(const App *app) const; - - /// This prints out all the groups of options - std::string make_groups(const App *app, AppFormatMode mode) const; - - /// This prints out all the subcommands - virtual std::string make_subcommands(const App *app, AppFormatMode mode) const; - - /// This prints out a subcommand - virtual std::string make_subcommand(const App *sub) const; - - /// This prints out a subcommand in help-all - virtual std::string make_expanded(const App *sub) const; - - /// This prints out all the groups of options - virtual std::string make_footer(const App *app) const; - - /// This displays the description line - virtual std::string make_description(const App *app) const; - - /// This displays the usage line - virtual std::string make_usage(const App *app, std::string name) const; - - /// This puts everything together - std::string make_help(const App * /*app*/, std::string, AppFormatMode) const override; - - ///@} - /// @name Options - ///@{ - - /// This prints out an option help line, either positional or optional form - virtual std::string make_option(const Option *opt, bool is_positional) const { - std::stringstream out; - detail::format_help( - out, make_option_name(opt, is_positional) + make_option_opts(opt), make_option_desc(opt), column_width_); - return out.str(); - } - - /// @brief This is the name part of an option, Default: left column - virtual std::string make_option_name(const Option *, bool) const; - - /// @brief This is the options part of the name, Default: combined into left column - virtual std::string make_option_opts(const Option *) const; - - /// @brief This is the description. Default: Right column, on new line if left column too large - virtual std::string make_option_desc(const Option *) const; - - /// @brief This is used to print the name on the USAGE line - virtual std::string make_option_usage(const Option *opt) const; - - ///@} -}; - - - - -using results_t = std::vector; -/// callback function definition -using callback_t = std::function; - -class Option; -class App; - -using Option_p = std::unique_ptr