initial commit
This commit is contained in:
130
internal/keybinds/providers/jsonfile.go
Normal file
130
internal/keybinds/providers/jsonfile.go
Normal file
@@ -0,0 +1,130 @@
|
||||
package providers
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/AvengeMedia/danklinux/internal/keybinds"
|
||||
)
|
||||
|
||||
type JSONFileProvider struct {
|
||||
filePath string
|
||||
name string
|
||||
}
|
||||
|
||||
func NewJSONFileProvider(filePath string) (*JSONFileProvider, error) {
|
||||
if filePath == "" {
|
||||
return nil, fmt.Errorf("file path cannot be empty")
|
||||
}
|
||||
|
||||
expandedPath, err := expandPath(filePath)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to expand path: %w", err)
|
||||
}
|
||||
|
||||
name := filepath.Base(expandedPath)
|
||||
name = name[:len(name)-len(filepath.Ext(name))]
|
||||
|
||||
return &JSONFileProvider{
|
||||
filePath: expandedPath,
|
||||
name: name,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (j *JSONFileProvider) Name() string {
|
||||
return j.name
|
||||
}
|
||||
|
||||
func (j *JSONFileProvider) GetCheatSheet() (*keybinds.CheatSheet, error) {
|
||||
data, err := os.ReadFile(j.filePath)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to read file: %w", err)
|
||||
}
|
||||
|
||||
var rawData map[string]interface{}
|
||||
if err := json.Unmarshal(data, &rawData); err != nil {
|
||||
return nil, fmt.Errorf("failed to parse JSON: %w", err)
|
||||
}
|
||||
|
||||
title, _ := rawData["title"].(string)
|
||||
provider, _ := rawData["provider"].(string)
|
||||
if provider == "" {
|
||||
provider = j.name
|
||||
}
|
||||
|
||||
categorizedBinds := make(map[string][]keybinds.Keybind)
|
||||
|
||||
bindsRaw, ok := rawData["binds"]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("missing 'binds' field")
|
||||
}
|
||||
|
||||
switch binds := bindsRaw.(type) {
|
||||
case map[string]interface{}:
|
||||
for category, categoryBindsRaw := range binds {
|
||||
categoryBindsList, ok := categoryBindsRaw.([]interface{})
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
var keybindsList []keybinds.Keybind
|
||||
categoryBindsJSON, _ := json.Marshal(categoryBindsList)
|
||||
if err := json.Unmarshal(categoryBindsJSON, &keybindsList); err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
categorizedBinds[category] = keybindsList
|
||||
}
|
||||
|
||||
case []interface{}:
|
||||
flatBindsJSON, _ := json.Marshal(binds)
|
||||
var flatBinds []struct {
|
||||
Key string `json:"key"`
|
||||
Description string `json:"desc"`
|
||||
Category string `json:"cat,omitempty"`
|
||||
Subcategory string `json:"subcat,omitempty"`
|
||||
}
|
||||
if err := json.Unmarshal(flatBindsJSON, &flatBinds); err != nil {
|
||||
return nil, fmt.Errorf("failed to parse flat binds array: %w", err)
|
||||
}
|
||||
|
||||
for _, bind := range flatBinds {
|
||||
category := bind.Category
|
||||
if category == "" {
|
||||
category = "Other"
|
||||
}
|
||||
|
||||
kb := keybinds.Keybind{
|
||||
Key: bind.Key,
|
||||
Description: bind.Description,
|
||||
Subcategory: bind.Subcategory,
|
||||
}
|
||||
categorizedBinds[category] = append(categorizedBinds[category], kb)
|
||||
}
|
||||
|
||||
default:
|
||||
return nil, fmt.Errorf("'binds' must be either an object (categorized) or array (flat)")
|
||||
}
|
||||
|
||||
return &keybinds.CheatSheet{
|
||||
Title: title,
|
||||
Provider: provider,
|
||||
Binds: categorizedBinds,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func expandPath(path string) (string, error) {
|
||||
expandedPath := os.ExpandEnv(path)
|
||||
|
||||
if filepath.HasPrefix(expandedPath, "~") {
|
||||
home, err := os.UserHomeDir()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
expandedPath = filepath.Join(home, expandedPath[1:])
|
||||
}
|
||||
|
||||
return filepath.Clean(expandedPath), nil
|
||||
}
|
||||
Reference in New Issue
Block a user