Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
X
ximperconf
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Ximper Linux
ximperconf
Commits
33f3fe93
Commit
33f3fe93
authored
Feb 15, 2026
by
Kirill Unitsaev
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
preset: post-apply config verification and error notification
parent
72107231
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
181 additions
and
5 deletions
+181
-5
presets.go
config/presets.go
+1
-0
status.go
config/status.go
+1
-1
actions.go
hyprland/actions.go
+36
-0
commands.go
hyprland/commands.go
+6
-0
manager.go
hyprland/manager.go
+19
-0
ru.po
po/ru.po
+35
-0
actions.go
preset/actions.go
+83
-4
No files found.
config/presets.go
View file @
33f3fe93
...
...
@@ -52,6 +52,7 @@ type HyprModule struct {
type
HyprlandEntry
struct
{
SyncLayouts
bool
`yaml:"sync-layouts,omitempty"`
Check
bool
`yaml:"check,omitempty"`
Vars
[]
HyprVar
`yaml:"vars,omitempty"`
Modules
[]
HyprModule
`yaml:"modules,omitempty"`
}
...
...
config/status.go
View file @
33f3fe93
...
...
@@ -107,7 +107,7 @@ var OpStatus = struct {
},
Skipped
:
ItemStatus
{
Symbol
:
"○"
,
Color
:
color
.
Yellow
String
,
Color
:
color
.
HiBlack
String
,
Label
:
"skipped"
,
},
DryRun
:
ItemStatus
{
...
...
hyprland/actions.go
View file @
33f3fe93
...
...
@@ -10,6 +10,7 @@ import (
"fmt"
"os"
"os/exec"
"path/filepath"
"strings"
"github.com/fatih/color"
...
...
@@ -344,6 +345,41 @@ func HyprlandModuleShowCommand(ctx context.Context, cmd *cli.Command) error {
return
nil
}
func
HyprlandNotifyErrorsCommand
(
ctx
context
.
Context
,
cmd
*
cli
.
Command
)
error
{
manager
,
err
:=
GetHyprlandManager
(
ctx
)
if
err
!=
nil
{
return
err
}
logPath
:=
filepath
.
Join
(
manager
.
Home
,
".cache"
,
"ximperconf"
,
"hyprland-check.log"
)
data
,
err
:=
os
.
ReadFile
(
logPath
)
logContent
:=
strings
.
TrimSpace
(
string
(
data
))
if
err
!=
nil
||
logContent
==
""
{
cleanupNotifyModule
(
manager
,
logPath
)
return
nil
}
text
:=
locale
.
T
(
"The following modules were disabled due to errors:"
)
+
"
\n\n
"
+
logContent
// Показываем диалог (блокирующий вызов)
dialogCmd
:=
exec
.
Command
(
"hyprland-dialog"
,
"--title"
,
locale
.
T
(
"Hyprland configuration errors"
),
"--text"
,
text
,
"--buttons"
,
"OK"
,
)
_
=
dialogCmd
.
Run
()
cleanupNotifyModule
(
manager
,
logPath
)
return
nil
}
func
cleanupNotifyModule
(
manager
*
HyprlandManager
,
logPath
string
)
{
manager
.
SetModule
(
"disable"
,
"ximperconf-errors"
,
false
,
false
)
os
.
Remove
(
logPath
)
}
func
getEditor
()
string
{
if
editor
:=
os
.
Getenv
(
"EDITOR"
);
editor
!=
""
{
return
editor
...
...
hyprland/commands.go
View file @
33f3fe93
...
...
@@ -33,6 +33,12 @@ func CommandList() *cli.Command {
},
Commands
:
[]
*
cli
.
Command
{
{
Name
:
"notify-errors"
,
Hidden
:
true
,
Usage
:
locale
.
T
(
"Show error notification dialog"
),
Action
:
HyprlandNotifyErrorsCommand
,
},
{
Name
:
"check"
,
Usage
:
locale
.
T
(
"Check the Hyprland config"
),
Action
:
HyprlandCheckCommand
,
...
...
hyprland/manager.go
View file @
33f3fe93
...
...
@@ -1092,6 +1092,25 @@ func (m *HyprlandManager) removeSource(lineNumber int) {
}
}
func
(
m
*
HyprlandManager
)
FindModuleByPath
(
filePath
string
)
(
name
string
,
isUser
bool
,
found
bool
)
{
allModules
:=
[]
struct
{
modules
[]
string
user
bool
}{
{
m
.
SystemModules
,
false
},
{
m
.
UserModules
,
true
},
}
for
_
,
group
:=
range
allModules
{
for
_
,
mod
:=
range
group
.
modules
{
if
m
.
GetModuleFile
(
mod
,
group
.
user
)
==
filePath
{
return
mod
,
group
.
user
,
true
}
}
}
return
""
,
false
,
false
}
func
(
m
*
HyprlandManager
)
scanModulesDir
(
user
bool
)
[]
string
{
dir
:=
m
.
GetModuleDir
(
user
)
...
...
po/ru.po
View file @
33f3fe93
...
...
@@ -715,6 +715,41 @@ msgstr "Категория:"
msgid "Global options:"
msgstr "Глобальные параметры:"
#: preset/actions.go
msgid "check"
msgstr "проверка"
#: preset/actions.go
#, c-format
msgid "Check failed: %v"
msgstr "Проверка не удалась: %v"
#: preset/actions.go
msgid "No errors found"
msgstr "Ошибок не найдено"
#: preset/actions.go
#, c-format
msgid "Module '%s' disabled (errors)"
msgstr "Модуль '%s' отключён (ошибки)"
#: preset/actions.go
#, c-format
msgid "Disabled %d module(s) with errors, log saved"
msgstr "Отключено модулей с ошибками: %d, лог сохранён"
#: hyprland/actions.go
msgid "Show error notification dialog"
msgstr "Показать диалог об ошибках"
#: hyprland/actions.go
msgid "The following modules were disabled due to errors:"
msgstr "Следующие модули были отключены из-за ошибок:"
#: hyprland/actions.go
msgid "Hyprland configuration errors"
msgstr "Ошибки конфигурации Hyprland"
#: ui/help.go:125
msgid "default"
msgstr "по умолчанию"
...
...
preset/actions.go
View file @
33f3fe93
...
...
@@ -6,6 +6,7 @@ import (
"fmt"
"os"
"os/exec"
"path/filepath"
"slices"
"sort"
"strings"
...
...
@@ -199,6 +200,76 @@ func processHyprModules(manager *hyprland.HyprlandManager, prof config.PresetPro
}
}
func
processVerifyModules
(
manager
*
hyprland
.
HyprlandManager
,
prof
config
.
PresetProfile
,
opts
opOptions
,
res
*
Result
)
{
if
!
prof
.
Hyprland
.
Check
||
opts
.
DryRun
{
return
}
if
manager
.
Changed
{
manager
.
Save
()
}
logPath
:=
filepath
.
Join
(
manager
.
Home
,
".cache"
,
"ximperconf"
,
"hyprland-check.log"
)
checkErrors
,
err
:=
manager
.
Check
(
""
)
if
err
!=
nil
{
res
.
Add
(
locale
.
T
(
"check"
),
fmt
.
Sprintf
(
locale
.
T
(
"Check failed: %v"
),
err
),
config
.
OpStatus
.
Error
)
return
}
if
len
(
checkErrors
)
==
0
{
os
.
Remove
(
logPath
)
// Удаляем лог от предыдущего запуска
res
.
Add
(
locale
.
T
(
"check"
),
locale
.
T
(
"No errors found"
),
config
.
OpStatus
.
Done
)
return
}
disabled
:=
map
[
string
]
bool
{}
var
logLines
[]
string
for
_
,
e
:=
range
checkErrors
{
name
,
isUser
,
found
:=
manager
.
FindModuleByPath
(
e
.
File
)
if
!
found
{
logLines
=
append
(
logLines
,
fmt
.
Sprintf
(
"config:%d - %s"
,
e
.
Line
,
e
.
Text
))
continue
}
prefix
:=
"system"
if
isUser
{
prefix
=
"user"
}
logLines
=
append
(
logLines
,
fmt
.
Sprintf
(
"%s/%s:%d - %s"
,
prefix
,
name
,
e
.
Line
,
e
.
Text
))
key
:=
prefix
+
"/"
+
name
if
disabled
[
key
]
{
continue
}
info
:=
manager
.
GetModuleInfo
(
name
,
isUser
)
if
!
info
.
Status
.
IsEqual
(
config
.
ModuleStatus
.
Enabled
)
{
continue
}
if
_
,
err
:=
manager
.
SetModule
(
"disable"
,
name
,
isUser
,
false
);
err
!=
nil
{
res
.
Add
(
locale
.
T
(
"check"
),
fmt
.
Sprintf
(
locale
.
T
(
"Failed to disable '%s': %v"
),
name
,
err
),
config
.
OpStatus
.
Error
)
continue
}
disabled
[
key
]
=
true
res
.
Add
(
locale
.
T
(
"check"
),
fmt
.
Sprintf
(
locale
.
T
(
"Module '%s' disabled (errors)"
),
name
),
config
.
OpStatus
.
Error
)
}
os
.
MkdirAll
(
filepath
.
Dir
(
logPath
),
0
o755
)
os
.
WriteFile
(
logPath
,
[]
byte
(
strings
.
Join
(
logLines
,
"
\n
"
)
+
"
\n
"
),
0
o644
)
if
len
(
disabled
)
==
0
{
return
}
// Включаем модуль уведомления об ошибках
if
_
,
err
:=
manager
.
SetModule
(
"enable"
,
"ximperconf-errors"
,
false
,
false
);
err
!=
nil
{
res
.
Add
(
locale
.
T
(
"check"
),
fmt
.
Sprintf
(
locale
.
T
(
"Failed to enable notification module: %v"
),
err
),
config
.
OpStatus
.
Error
)
}
}
func
processHyprLayoutSync
(
manager
*
hyprland
.
HyprlandManager
,
prof
config
.
PresetProfile
,
opts
opOptions
,
res
*
Result
)
{
if
!
prof
.
Hyprland
.
SyncLayouts
{
return
...
...
@@ -243,6 +314,7 @@ func processProfile(prof config.PresetProfile, opts opOptions, res *Result, mana
processHyprVars
(
manager
,
prof
,
opts
,
res
)
processHyprModules
(
manager
,
prof
,
opts
,
res
)
processHyprLayoutSync
(
manager
,
prof
,
opts
,
res
)
processVerifyModules
(
manager
,
prof
,
opts
,
res
)
}
}
...
...
@@ -281,17 +353,21 @@ func presetApplyCommand(ctx context.Context, cmd *cli.Command) error {
Force
:
cmd
.
Bool
(
"force"
),
}
manager
:=
tryCreateManager
()
var
manager
*
hyprland
.
HyprlandManager
if
strings
.
EqualFold
(
prof
.
Binary
,
"hyprland"
)
{
manager
=
tryCreateManager
()
}
res
:=
&
Result
{}
color
.
Green
(
locale
.
T
(
"Applying profile: %s"
),
profileName
)
processProfile
(
prof
,
opts
,
res
,
manager
)
res
.
Render
()
if
manager
!=
nil
&&
manager
.
Changed
&&
!
opts
.
DryRun
{
manager
.
Save
()
}
res
.
Render
()
return
nil
}
...
...
@@ -327,13 +403,16 @@ func presetApplyAllCommand(ctx context.Context, cmd *cli.Command) error {
Force
:
cmd
.
Bool
(
"force"
),
}
manager
:=
tryCreateManager
()
var
manager
*
hyprland
.
HyprlandManager
for
_
,
np
:=
range
sortedProfiles
(
profiles
)
{
if
!
profileAvailable
(
np
.
Profile
)
{
continue
}
if
manager
==
nil
&&
strings
.
EqualFold
(
np
.
Profile
.
Binary
,
"hyprland"
)
{
manager
=
tryCreateManager
()
}
res
:=
&
Result
{}
color
.
Green
(
locale
.
T
(
"Applying profile: %s"
),
np
.
Name
)
processProfile
(
np
.
Profile
,
opts
,
res
,
manager
)
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment