mirror of
https://github.com/JanDeDobbeleer/oh-my-posh.git
synced 2025-01-11 11:17:27 -08:00
feat(font): allow installing from a specific zip file folder
Some checks are pending
Code QL / code-ql (push) Waiting to run
Azure Static Web Apps CI/CD / Build and Deploy (push) Waiting to run
Release / changelog (push) Waiting to run
Release / artifacts (push) Blocked by required conditions
Release / msi (arm64) (push) Blocked by required conditions
Release / msi (x64) (push) Blocked by required conditions
Release / msi (x86) (push) Blocked by required conditions
Release / release (push) Blocked by required conditions
Some checks are pending
Code QL / code-ql (push) Waiting to run
Azure Static Web Apps CI/CD / Build and Deploy (push) Waiting to run
Release / changelog (push) Waiting to run
Release / artifacts (push) Blocked by required conditions
Release / msi (arm64) (push) Blocked by required conditions
Release / msi (x64) (push) Blocked by required conditions
Release / msi (x86) (push) Blocked by required conditions
Release / release (push) Blocked by required conditions
This commit is contained in:
parent
b4b2fd02d5
commit
a7ad857a2d
|
@ -11,7 +11,7 @@ import (
|
|||
)
|
||||
|
||||
var (
|
||||
ttf bool
|
||||
zipFolder string
|
||||
|
||||
fontCmd = &cobra.Command{
|
||||
Use: "font [install|configure]",
|
||||
|
@ -47,7 +47,7 @@ This command is used to install fonts and configure the font in your terminal.
|
|||
|
||||
terminal.Init(env.Shell())
|
||||
|
||||
font.Run(fontName, env.Cache(), env.Root(), ttf)
|
||||
font.Run(fontName, env.Cache(), env.Root(), zipFolder)
|
||||
|
||||
return
|
||||
case "configure":
|
||||
|
@ -60,6 +60,6 @@ This command is used to install fonts and configure the font in your terminal.
|
|||
)
|
||||
|
||||
func init() {
|
||||
fontCmd.Flags().BoolVar(&ttf, "ttf", false, "fetch the TTF version of the font")
|
||||
fontCmd.Flags().StringVar(&zipFolder, "zip-folder", "", "the folder inside the zip file to install fonts from")
|
||||
RootCmd.AddCommand(fontCmd)
|
||||
}
|
||||
|
|
|
@ -72,14 +72,14 @@ const (
|
|||
)
|
||||
|
||||
type main struct {
|
||||
err error
|
||||
list *list.Model
|
||||
font string
|
||||
families []string
|
||||
spinner spinner.Model
|
||||
state state
|
||||
system bool
|
||||
ttf bool
|
||||
err error
|
||||
list *list.Model
|
||||
font string
|
||||
zipFolder string
|
||||
families []string
|
||||
spinner spinner.Model
|
||||
state state
|
||||
system bool
|
||||
}
|
||||
|
||||
func (m *main) buildFontList(nerdFonts []*Asset) {
|
||||
|
@ -121,18 +121,18 @@ func downloadFontZip(location string) {
|
|||
program.Send(zipMsg(zipFile))
|
||||
}
|
||||
|
||||
func installLocalFontZIP(zipFile string, user, ttf bool) {
|
||||
data, err := os.ReadFile(zipFile)
|
||||
func installLocalFontZIP(m *main) {
|
||||
data, err := os.ReadFile(m.font)
|
||||
if err != nil {
|
||||
program.Send(errMsg(err))
|
||||
return
|
||||
}
|
||||
|
||||
installFontZIP(data, user, ttf)
|
||||
installFontZIP(data, m)
|
||||
}
|
||||
|
||||
func installFontZIP(zipFile []byte, user, ttf bool) {
|
||||
families, err := InstallZIP(zipFile, user, ttf)
|
||||
func installFontZIP(zipFile []byte, m *main) {
|
||||
families, err := InstallZIP(zipFile, m)
|
||||
if err != nil {
|
||||
program.Send(errMsg(err))
|
||||
return
|
||||
|
@ -148,21 +148,30 @@ func (m *main) Init() tea.Cmd {
|
|||
|
||||
if len(m.font) != 0 && !isLocalZipFile() {
|
||||
m.state = downloadFont
|
||||
|
||||
if !strings.HasPrefix(m.font, "https") {
|
||||
m.font = fmt.Sprintf("https://github.com/ryanoasis/nerd-fonts/releases/latest/download/%s.zip", m.font)
|
||||
if strings.HasPrefix(m.font, "CascadiaCode-") {
|
||||
version := strings.TrimPrefix(m.font, "CascadiaCode-")
|
||||
m.font = fmt.Sprintf("https://github.com/microsoft/cascadia-code/releases/download/v%s/%s.zip", version, m.font)
|
||||
} else {
|
||||
m.font = fmt.Sprintf("https://github.com/ryanoasis/nerd-fonts/releases/latest/download/%s.zip", m.font)
|
||||
}
|
||||
}
|
||||
|
||||
defer func() {
|
||||
go downloadFontZip(m.font)
|
||||
}()
|
||||
|
||||
m.spinner.Spinner = spinner.Globe
|
||||
return m.spinner.Tick
|
||||
}
|
||||
|
||||
defer func() {
|
||||
if isLocalZipFile() {
|
||||
go installLocalFontZIP(m.font, m.system, m.ttf)
|
||||
go installLocalFontZIP(m)
|
||||
return
|
||||
}
|
||||
|
||||
go getFontsList()
|
||||
}()
|
||||
|
||||
|
@ -171,6 +180,7 @@ func (m *main) Init() tea.Cmd {
|
|||
s.Style = lipgloss.NewStyle().Foreground(lipgloss.Color("170"))
|
||||
m.spinner = s
|
||||
m.state = getFonts
|
||||
|
||||
if isLocalZipFile() {
|
||||
m.state = unzipFont
|
||||
}
|
||||
|
@ -240,7 +250,7 @@ func (m *main) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
|||
case zipMsg:
|
||||
m.state = installFont
|
||||
defer func() {
|
||||
go installFontZIP(msg, m.system, m.ttf)
|
||||
go installFontZIP(msg, m)
|
||||
}()
|
||||
m.spinner.Spinner = spinner.Dot
|
||||
return m, m.spinner.Tick
|
||||
|
@ -288,6 +298,10 @@ func (m *main) View() string {
|
|||
case quit:
|
||||
return textStyle.Render(fmt.Sprintf("No need to install a new font? That's cool.%s", terminal.StopProgress()))
|
||||
case done:
|
||||
if len(m.families) == 0 {
|
||||
return textStyle.Render(fmt.Sprintf("No matching font families were installed. Try setting --zip-folder to the correct folder when using Cascadia Code or a custom font zip file %s", terminal.StopProgress())) //nolint: lll
|
||||
}
|
||||
|
||||
var builder strings.Builder
|
||||
|
||||
builder.WriteString(fmt.Sprintf("Successfully installed %s 🚀\n\n%s", m.font, terminal.StopProgress()))
|
||||
|
@ -307,11 +321,11 @@ func (m *main) View() string {
|
|||
return ""
|
||||
}
|
||||
|
||||
func Run(font string, ch cache_.Cache, root, ttf bool) {
|
||||
func Run(font string, ch cache_.Cache, root bool, zipFolder string) {
|
||||
main := &main{
|
||||
font: font,
|
||||
system: root,
|
||||
ttf: ttf,
|
||||
font: font,
|
||||
system: root,
|
||||
zipFolder: zipFolder,
|
||||
}
|
||||
|
||||
cache = ch
|
||||
|
|
|
@ -25,13 +25,7 @@ func contains[S ~[]E, E comparable](s S, e E) bool {
|
|||
return false
|
||||
}
|
||||
|
||||
func InstallZIP(data []byte, user, ttf bool) ([]string, error) {
|
||||
// prefer OTF over TTF; otherwise prefer the first font we find
|
||||
extension := ".otf"
|
||||
if ttf {
|
||||
extension = ".ttf"
|
||||
}
|
||||
|
||||
func InstallZIP(data []byte, m *main) ([]string, error) {
|
||||
var families []string
|
||||
bytesReader := bytes.NewReader(data)
|
||||
|
||||
|
@ -42,46 +36,56 @@ func InstallZIP(data []byte, user, ttf bool) ([]string, error) {
|
|||
|
||||
fonts := make(map[string]*Font)
|
||||
|
||||
for _, zf := range zipReader.File {
|
||||
root := len(m.zipFolder) == 0
|
||||
|
||||
for _, file := range zipReader.File {
|
||||
// prevent zipslip attacks
|
||||
// https://security.snyk.io/research/zip-slip-vulnerability
|
||||
if strings.Contains(zf.Name, "..") {
|
||||
// and only process files which are in the specified folder
|
||||
if strings.Contains(file.Name, "..") || !strings.HasPrefix(file.Name, m.zipFolder) {
|
||||
continue
|
||||
}
|
||||
|
||||
rc, err := zf.Open()
|
||||
if err != nil {
|
||||
return families, err
|
||||
fontFileName := path.Base(file.Name)
|
||||
|
||||
// do not install fonts that are not in the root folder when specified as such
|
||||
if root && fontFileName != file.Name {
|
||||
continue
|
||||
}
|
||||
|
||||
defer rc.Close()
|
||||
|
||||
data, err := io.ReadAll(rc)
|
||||
if err != nil {
|
||||
return families, err
|
||||
}
|
||||
|
||||
fontData, err := newFont(path.Base(zf.Name), data)
|
||||
fontReader, err := file.Open()
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
if _, found := fonts[fontData.Name]; !found {
|
||||
fonts[fontData.Name] = fontData
|
||||
defer fontReader.Close()
|
||||
|
||||
fontBytes, err := io.ReadAll(fontReader)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
// respect the user's preference for TTF or OTF
|
||||
first := strings.ToLower(path.Ext(fonts[fontData.Name].FileName))
|
||||
second := strings.ToLower(path.Ext(fontData.FileName))
|
||||
if first != second && second == extension {
|
||||
fonts[fontData.Name] = fontData
|
||||
font, err := newFont(fontFileName, fontBytes)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
if _, found := fonts[font.Name]; !found {
|
||||
fonts[font.Name] = font
|
||||
continue
|
||||
}
|
||||
|
||||
// prefer .ttf files over other file types when we have a duplicate
|
||||
first := strings.ToLower(path.Ext(fonts[font.Name].FileName))
|
||||
second := strings.ToLower(path.Ext(font.FileName))
|
||||
if first != second && second == ".ttf" {
|
||||
fonts[font.Name] = font
|
||||
}
|
||||
}
|
||||
|
||||
for _, font := range fonts {
|
||||
if err = install(font, user); err != nil {
|
||||
return families, err
|
||||
if err = install(font, m.system); err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
if found := contains(families, font.Family); !found {
|
||||
|
|
|
@ -34,6 +34,7 @@ Oh My Posh has a CLI to help you select and install a [Nerd Font][nerdfonts]:
|
|||
:::info
|
||||
When running as root/administrator, the fonts will be installed system-wide.
|
||||
When running as a regular user, the fonts will be installed in the user's font directory.
|
||||
By default, Oh My Posh installs the `.ttf` version of the font in case multiple versions are available.
|
||||
:::
|
||||
|
||||
```bash
|
||||
|
@ -46,10 +47,10 @@ This will present a list of Nerd Font libraries, from which you can select `Mes
|
|||
oh-my-posh font install meslo
|
||||
```
|
||||
|
||||
By default, Oh My Posh installs the `.otf` version of the font. If you prefer the `.ttf` version, you can specify it with the `--ttf` flag:
|
||||
If you have a font that has specific flavors of a font inside sub folders, you can specify the sub folder name:
|
||||
|
||||
```bash
|
||||
oh-my-posh font install meslo --ttf
|
||||
oh-my-posh font install --zip-folder ttf/static CascadiaCode-2407.24
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
|
|
Loading…
Reference in a new issue