hyprland/module: add dependency system

parent f1638e59
......@@ -190,6 +190,15 @@ func HyprlandToggleModuleCommand(ctx context.Context, cmd *cli.Command) error {
func HyprlandInfoModulesCommand(ctx context.Context, cmd *cli.Command) error {
filter := cmd.String("filter")
// Скрывать модули с отсутствующими зависимостями по умолчанию
if !strings.Contains(filter, "all") && !strings.Contains(filter, "deps:") {
if filter == "" {
filter = "deps:installed"
} else {
filter += ",deps:installed"
}
}
manager, err := GetHyprlandManager(ctx)
if err != nil {
return err
......@@ -224,6 +233,7 @@ func HyprlandInfoModulesCommand(ctx context.Context, cmd *cli.Command) error {
Name: d.info.ShortName(),
User: d.info.User,
Status: d.info.Status.Label,
DepsInstalled: d.info.DepsInstalled,
Errors: d.errorNum,
}
if d.info.Meta != nil {
......@@ -247,6 +257,12 @@ func HyprlandInfoModulesCommand(ctx context.Context, cmd *cli.Command) error {
if d.info.Meta != nil && d.info.Meta.Group != "" {
name = d.info.Meta.Group + "/" + name
}
if !d.info.DepsInstalled {
missing := missingDeps(d.info.Meta)
if len(missing) > 0 {
parts = append(parts, fmt.Sprintf("(requires: %s)", strings.Join(missing, ", ")))
}
}
item := ui.TreeItem{
Name: name,
Status: d.info.Status,
......@@ -285,6 +301,15 @@ func HyprlandInfoModulesCommand(ctx context.Context, cmd *cli.Command) error {
func HyprlandModuleListCommand(ctx context.Context, cmd *cli.Command) error {
filter := cmd.String("filter")
// Скрывать модули с отсутствующими зависимостями по умолчанию
if !strings.Contains(filter, "all") && !strings.Contains(filter, "deps:") {
if filter == "" {
filter = "deps:installed"
} else {
filter += ",deps:installed"
}
}
manager, err := GetHyprlandManager(ctx)
if err != nil {
return err
......@@ -381,6 +406,17 @@ func HyprlandModuleShowCommand(ctx context.Context, cmd *cli.Command) error {
}
}
fmt.Printf("%s: %s\n", blue(locale.T("Status")), info.Status.Color("%s %s", info.Status.Symbol, info.Status.Label))
if info.Meta != nil && len(info.Meta.Requires) > 0 {
var deps []string
for _, bin := range info.Meta.Requires {
if _, err := exec.LookPath(bin); err == nil {
deps = append(deps, color.GreenString("✓")+" "+bin)
} else {
deps = append(deps, color.RedString("✗")+" "+bin)
}
}
fmt.Printf("%s: %s\n", blue(locale.T("Dependencies")), strings.Join(deps, ", "))
}
fmt.Printf("%s: %s\n", blue(locale.T("Path")), info.Path)
fmt.Printf("%s: %s\n", blue(locale.T("Config path")), info.ConfPath)
fmt.Printf("%s: %d\n", blue(locale.T("Config line")), info.LineNumber)
......
......@@ -71,21 +71,21 @@ func CommandList() *cli.Command {
ArgsUsage: "module",
Flags: []cli.Flag{config.FormatFlag},
Action: HyprlandModuleCheckCommand,
ShellComplete: ShellCompleteModule(""),
ShellComplete: ShellCompleteModule("all"),
},
{
Name: "edit",
Usage: locale.T("Edit module file"),
ArgsUsage: "module",
Action: HyprlandModuleEditCommand,
ShellComplete: ShellCompleteModule(""),
ShellComplete: ShellCompleteModule("all"),
},
{
Name: "status",
Usage: locale.T("Hyprland module status"),
ArgsUsage: "module",
Action: HyprlandModuleStatusCommand,
ShellComplete: ShellCompleteModule(""),
ShellComplete: ShellCompleteModule("all"),
},
{
Name: "show",
......@@ -95,7 +95,7 @@ func CommandList() *cli.Command {
config.FormatFlag,
},
Action: HyprlandModuleShowCommand,
ShellComplete: ShellCompleteModule(""),
ShellComplete: ShellCompleteModule("all"),
},
{
Name: "list",
......@@ -103,7 +103,7 @@ func CommandList() *cli.Command {
Flags: []cli.Flag{
&cli.StringFlag{
Name: "filter",
Usage: locale.T("module filter (e.g. status:enabled, type:user, group:themes)"),
Usage: locale.T("module filter (e.g. status:enabled, type:user, group:themes, deps:installed)"),
Aliases: []string{"f"},
},
config.FormatFlag,
......@@ -116,7 +116,7 @@ func CommandList() *cli.Command {
Flags: []cli.Flag{
&cli.StringFlag{
Name: "filter",
Usage: locale.T("module filter (e.g. status:enabled, type:user, group:themes)"),
Usage: locale.T("module filter (e.g. status:enabled, type:user, group:themes, deps:installed)"),
Aliases: []string{"f"},
},
config.FormatFlag,
......@@ -128,7 +128,7 @@ func CommandList() *cli.Command {
Usage: locale.T("enable module"),
ArgsUsage: "module",
Action: HyprlandModuleEnableCommand,
ShellComplete: ShellCompleteModule("status:disabled"),
ShellComplete: ShellCompleteModule("status:noenabled,deps:installed"),
},
{
Name: "disable",
......@@ -150,7 +150,7 @@ func CommandList() *cli.Command {
Usage: locale.T("toggle module"),
ArgsUsage: "module",
Action: HyprlandToggleModuleCommand,
ShellComplete: ShellCompleteModule(""),
ShellComplete: ShellCompleteModule("deps:installed"),
},
},
},
......
......@@ -16,5 +16,6 @@ type ModuleInfoJSON struct {
Group string `json:"group"`
Summary string `json:"summary"`
Status string `json:"status"`
DepsInstalled bool `json:"deps_installed"`
Errors int `json:"errors"`
}
......@@ -44,6 +44,7 @@ type HyprModule struct {
ConfPath string `json:"conf_path"`
LineNumber int `json:"line_number"`
Available bool `json:"available"`
DepsInstalled bool `json:"deps_installed"`
Meta *ModuleMeta `json:"meta,omitempty"`
}
......@@ -216,11 +217,37 @@ func (m *HyprlandManager) GetModuleInfo(module string) HyprModule {
Name: module,
Status: config.ModuleStatus.Unknown,
Available: !slices.Contains(config.HyprlandSkipModules, module),
DepsInstalled: true,
}
}
return m.getModuleInfo(fullName, user)
}
func checkDeps(meta *ModuleMeta) bool {
if meta == nil || len(meta.Requires) == 0 {
return true
}
for _, bin := range meta.Requires {
if _, err := exec.LookPath(bin); err != nil {
return false
}
}
return true
}
func missingDeps(meta *ModuleMeta) []string {
if meta == nil {
return nil
}
var missing []string
for _, bin := range meta.Requires {
if _, err := exec.LookPath(bin); err != nil {
missing = append(missing, bin)
}
}
return missing
}
func (m *HyprlandManager) getModuleInfo(module string, user bool) HyprModule {
modulePath := m.GetModuleFile(module, user)
......@@ -237,6 +264,7 @@ func (m *HyprlandManager) getModuleInfo(module string, user bool) HyprModule {
// Конфиг Hyprland отсутствует
if !config.FileExists(config.Env.Hyprland.Config) {
if fileExists {
meta := ParseModuleMeta(modulePath)
return HyprModule{
Name: module,
User: user,
......@@ -244,7 +272,8 @@ func (m *HyprlandManager) getModuleInfo(module string, user bool) HyprModule {
Path: modulePath,
ConfPath: confPath,
Available: available,
Meta: ParseModuleMeta(modulePath),
DepsInstalled: checkDeps(meta),
Meta: meta,
}
}
return HyprModule{
......@@ -252,6 +281,7 @@ func (m *HyprlandManager) getModuleInfo(module string, user bool) HyprModule {
User: user,
Status: config.ModuleStatus.Missing,
Available: available,
DepsInstalled: true,
}
}
......@@ -285,9 +315,11 @@ func (m *HyprlandManager) getModuleInfo(module string, user bool) HyprModule {
Status: config.ModuleStatus.Missing,
LineNumber: lineNumber,
Available: available,
DepsInstalled: true,
}
}
// файл есть
meta := ParseModuleMeta(modulePath)
return HyprModule{
Name: module,
User: user,
......@@ -296,7 +328,8 @@ func (m *HyprlandManager) getModuleInfo(module string, user bool) HyprModule {
ConfPath: confPath,
LineNumber: lineNumber,
Available: available,
Meta: ParseModuleMeta(modulePath),
DepsInstalled: checkDeps(meta),
Meta: meta,
}
}
......@@ -310,9 +343,11 @@ func (m *HyprlandManager) getModuleInfo(module string, user bool) HyprModule {
ConfPath: confPath,
LineNumber: lineNumber,
Available: available,
DepsInstalled: true,
}
if fileExists {
mod.Meta = ParseModuleMeta(modulePath)
mod.DepsInstalled = checkDeps(mod.Meta)
} else {
mod.Path = ""
}
......@@ -321,6 +356,7 @@ func (m *HyprlandManager) getModuleInfo(module string, user bool) HyprModule {
// файл есть, но строка отсутствует
if fileExists {
meta := ParseModuleMeta(modulePath)
return HyprModule{
Name: module,
User: user,
......@@ -328,7 +364,8 @@ func (m *HyprlandManager) getModuleInfo(module string, user bool) HyprModule {
Path: modulePath,
ConfPath: confPath,
Available: available,
Meta: ParseModuleMeta(modulePath),
DepsInstalled: checkDeps(meta),
Meta: meta,
}
}
......@@ -338,6 +375,7 @@ func (m *HyprlandManager) getModuleInfo(module string, user bool) HyprModule {
User: user,
Status: config.ModuleStatus.Unknown,
Available: available,
DepsInstalled: true,
}
}
......@@ -435,6 +473,19 @@ func matchModuleFilter(info HyprModule, filters map[string]string) bool {
}
}
if v, ok := filters["deps"]; ok {
switch v {
case "installed":
if !info.DepsInstalled {
return false
}
case "uninstalled":
if info.DepsInstalled {
return false
}
}
}
return true
}
......@@ -451,6 +502,12 @@ func (m *HyprlandManager) SetModule(action, module string, onlyNew bool) (string
switch action {
case "enable":
// зависимости не установлены
if !info.DepsInstalled {
return "", fmt.Errorf(locale.T("missing module dependencies: %s"),
strings.Join(missingDeps(info.Meta), ", "))
}
// нет файла
if info.Path == "" || info.Status.IsEqual(config.ModuleStatus.Unknown) {
return "", errors.New(locale.T("cannot enable this module"))
......
......@@ -14,6 +14,7 @@ type ModuleMeta struct {
Description string `yaml:"description,omitempty"`
Group string `yaml:"group,omitempty"`
Order int `yaml:"order,omitempty"`
Requires []string `yaml:"requires,omitempty"`
}
func ParseModuleMeta(filePath string) *ModuleMeta {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment