1
0
mirror of https://github.com/AvengeMedia/DankMaterialShell.git synced 2026-05-02 10:32:07 -04:00

Compare commits

...

17 Commits

Author SHA1 Message Date
bbedward
bb08e1233a matugen: bump default queue timeout to 90s 2026-03-13 15:40:55 -04:00
bbedward
5343e97ab2 core/server: initialize geolocation async on startup 2026-03-13 15:06:11 -04:00
purian23
edc544df7a dms(policy): Restore dms greeter sync in immutable distros 2026-03-13 14:27:15 -04:00
bbedward
a880edd9fb core: restore core go version to 1.26.0 2026-03-13 13:40:11 -04:00
Jonas Bloch
7e1d808d70 New neovim theme engine (#1985)
* feat(matugen)!: rework completely neovim's theme engine

* fix: link to neovim theme plugin

* fix: expect AvengeMedia/base46 instead of Silzinc/base46
2026-03-13 13:37:16 -04:00
bbedward
ce93f22669 chore: Makefile shouldnt build when installing 2026-03-13 13:36:44 -04:00
bbedward
a58037b968 fix: missing import in Hyprland service 2026-03-13 13:25:20 -04:00
bbedward
ccf0b60935 core: add toolchain directive to go.mod 2026-03-13 13:05:31 -04:00
bbedward
aad7011b1c ci: fix hardcoded branch in vendor workflow 2026-03-13 12:22:27 -04:00
bbedward
3bde7ef4d3 nix: update flake 2026-03-13 12:13:58 -04:00
bbedward
04555dbfa7 nix: fix go regex matching 2026-03-13 12:03:42 -04:00
bbedward
3b494aa591 nix: dynamically resolve go version in flake 2026-03-13 11:58:08 -04:00
bbedward
365387c3cd ci: reveal errors in nix vendor hash update 2026-03-13 11:53:17 -04:00
Nek
bb74a0ca4d fix(wallpaper): preserve per-monitor cycling when changing interval (#1981)
(#1816)
2026-03-13 11:46:02 -04:00
nick-linux8
9cf2ef84b7 Added Better Handling In Event Dispatcher Function (#1980) 2026-03-13 11:43:24 -04:00
bbedward
46aaf5ff77 fix(udev): avoid event loop termination
core: bump go to 1.26
2026-03-13 11:42:46 -04:00
Nek
c544bda5df fix(matugen): detect Zed Linux binary aliases (#1982) 2026-03-13 11:29:51 -04:00
33 changed files with 1537 additions and 868 deletions

View File

@@ -40,7 +40,7 @@ jobs:
echo "Build succeeded, no hash update needed"
exit 0
fi
new_hash=$(echo "$output" | grep -oP "got:\s+\K\S+" | head -n1)
new_hash=$(echo "$output" | grep -oP "got:\s+\K\S+" | head -n1 || true)
[ -n "$new_hash" ] || { echo "Could not extract new vendorHash"; echo "$output"; exit 1; }
current_hash=$(grep -oP 'vendorHash = "\K[^"]+' flake.nix)
[ "$current_hash" = "$new_hash" ] && { echo "vendorHash already up to date"; exit 0; }
@@ -59,8 +59,8 @@ jobs:
git config user.email "dms-ci[bot]@users.noreply.github.com"
git add flake.nix
git commit -m "nix: update vendorHash for go.mod changes" || exit 0
git pull --rebase origin master
git push https://x-access-token:${GH_TOKEN}@github.com/${{ github.repository }}.git HEAD:master
git pull --rebase origin ${{ github.ref_name }}
git push https://x-access-token:${GH_TOKEN}@github.com/${{ github.repository }}.git HEAD:${{ github.ref_name }}
else
echo "No changes to flake.nix"
fi

View File

@@ -79,7 +79,7 @@ install-desktop:
@update-desktop-database -q $(APPLICATIONS_DIR) 2>/dev/null || true
@echo "Desktop entry installed"
install: build install-bin install-shell install-completions install-systemd install-icon install-desktop
install: install-bin install-shell install-completions install-systemd install-icon install-desktop
@echo ""
@echo "Installation complete!"
@echo ""

View File

@@ -1,13 +1,26 @@
repos:
- repo: https://github.com/golangci/golangci-lint
rev: v2.9.0
hooks:
- id: golangci-lint-fmt
require_serial: true
- id: golangci-lint-full
- id: golangci-lint-config-verify
- repo: local
hooks:
- id: golangci-lint-fmt
name: golangci-lint-fmt
entry: go run github.com/golangci/golangci-lint/v2/cmd/golangci-lint@v2.11.3 fmt
language: system
require_serial: true
types: [go]
pass_filenames: false
- id: golangci-lint-full
name: golangci-lint-full
entry: go run github.com/golangci/golangci-lint/v2/cmd/golangci-lint@v2.11.3 run --fix
language: system
require_serial: true
types: [go]
pass_filenames: false
- id: golangci-lint-config-verify
name: golangci-lint-config-verify
entry: go run github.com/golangci/golangci-lint/v2/cmd/golangci-lint@v2.11.3 config verify
language: system
files: \.golangci\.(?:yml|yaml|toml|json)
pass_filenames: false
- id: go-test
name: go test
entry: go test ./...

View File

@@ -63,19 +63,19 @@ endif
build-all: build dankinstall
install: build
install:
@echo "Installing $(BINARY_NAME) to $(INSTALL_DIR)..."
@install -D -m 755 $(BUILD_DIR)/$(BINARY_NAME) $(INSTALL_DIR)/$(BINARY_NAME)
@echo "Installation complete"
install-all: build-all
install-all:
@echo "Installing $(BINARY_NAME) to $(INSTALL_DIR)..."
@install -D -m 755 $(BUILD_DIR)/$(BINARY_NAME) $(INSTALL_DIR)/$(BINARY_NAME)
@echo "Installing $(BINARY_NAME_INSTALL) to $(INSTALL_DIR)..."
@install -D -m 755 $(BUILD_DIR)/$(BINARY_NAME_INSTALL) $(INSTALL_DIR)/$(BINARY_NAME_INSTALL)
@echo "Installation complete"
install-dankinstall: dankinstall
install-dankinstall:
@echo "Installing $(BINARY_NAME_INSTALL) to $(INSTALL_DIR)..."
@install -D -m 755 $(BUILD_DIR)/$(BINARY_NAME_INSTALL) $(INSTALL_DIR)/$(BINARY_NAME_INSTALL)
@echo "Installation complete"

View File

@@ -3,7 +3,6 @@
"blocked_commands": [
"greeter install",
"greeter enable",
"greeter sync",
"greeter uninstall",
"setup"
],

View File

@@ -1079,14 +1079,14 @@ func formatResultsPlain(results []checkResult) string {
if currentCategory != -1 {
sb.WriteString("\n")
}
sb.WriteString(fmt.Sprintf("**%s**\n", r.category.String()))
fmt.Fprintf(&sb, "**%s**\n", r.category.String())
currentCategory = r.category
}
sb.WriteString(fmt.Sprintf("- [%s] %s: %s\n", r.status, r.name, r.message))
fmt.Fprintf(&sb, "- [%s] %s: %s\n", r.status, r.name, r.message)
if doctorVerbose && r.details != "" {
sb.WriteString(fmt.Sprintf(" - %s\n", r.details))
fmt.Fprintf(&sb, " - %s\n", r.details)
}
}
@@ -1096,8 +1096,8 @@ func formatResultsPlain(results []checkResult) string {
}
sb.WriteString("\n---\n")
sb.WriteString(fmt.Sprintf("**Summary:** %d error(s), %d warning(s), %d ok\n",
ds.ErrorCount(), ds.WarningCount(), ds.OKCount()))
fmt.Fprintf(&sb, "**Summary:** %d error(s), %d warning(s), %d ok\n",
ds.ErrorCount(), ds.WarningCount(), ds.OKCount())
return sb.String()
}

View File

@@ -51,10 +51,9 @@ var greeterInstallCmd = &cobra.Command{
}
var greeterSyncCmd = &cobra.Command{
Use: "sync",
Short: "Sync DMS theme and settings with greeter",
Long: "Synchronize your current user's DMS theme, settings, and wallpaper configuration with the login greeter screen",
PreRunE: requireMutableSystemCommand,
Use: "sync",
Short: "Sync DMS theme and settings with greeter",
Long: "Synchronize your current user's DMS theme, settings, and wallpaper configuration with the login greeter screen",
Run: func(cmd *cobra.Command, args []string) {
yes, _ := cmd.Flags().GetBool("yes")
auth, _ := cmd.Flags().GetBool("auth")

View File

@@ -60,7 +60,7 @@ func init() {
}
matugenQueueCmd.Flags().Bool("wait", true, "Wait for completion")
matugenQueueCmd.Flags().Duration("timeout", 30*time.Second, "Timeout for waiting")
matugenQueueCmd.Flags().Duration("timeout", 90*time.Second, "Timeout for waiting")
}
func buildMatugenOptions(cmd *cobra.Command) matugen.Options {

View File

@@ -213,7 +213,7 @@ func getImmutablePolicy() (*immutableCommandPolicy, error) {
immutablePolicy = immutableCommandPolicy{
ImmutableSystem: detectedImmutable,
ImmutableReason: reason,
BlockedCommands: []string{"greeter install", "greeter enable", "greeter sync", "setup"},
BlockedCommands: []string{"greeter install", "greeter enable", "setup"},
Message: "This command is disabled on immutable/image-based systems. Use your distro-native workflow for system-level changes.",
}

View File

@@ -1,6 +1,8 @@
module github.com/AvengeMedia/DankMaterialShell/core
go 1.25.0
go 1.26.0
toolchain go1.26.1
require (
github.com/Wifx/gonetworkmanager/v2 v2.2.0

View File

@@ -71,7 +71,7 @@ var templateRegistry = []TemplateDef{
{ID: "kcolorscheme", ConfigFile: "kcolorscheme.toml", RunUnconditionally: true},
{ID: "vscode", Kind: TemplateKindVSCode},
{ID: "emacs", Commands: []string{"emacs"}, ConfigFile: "emacs.toml", Kind: TemplateKindEmacs},
{ID: "zed", Commands: []string{"zed"}, ConfigFile: "zed.toml"},
{ID: "zed", Commands: []string{"zed", "zeditor", "zedit"}, ConfigFile: "zed.toml"},
}
func (c *ColorMode) GTKTheme() string {

View File

@@ -6,12 +6,20 @@ import (
"strconv"
"strings"
"sync"
"syscall"
"time"
"github.com/AvengeMedia/DankMaterialShell/core/internal/log"
"github.com/pilebones/go-udev/netlink"
)
const (
udevRecvBufSize = 8 * 1024 * 1024
udevMaxRetries = 5
udevBaseDelay = 2 * time.Second
udevMaxDelay = 60 * time.Second
)
type UdevMonitor struct {
stop chan struct{}
rescanMutex sync.Mutex
@@ -29,13 +37,6 @@ func NewUdevMonitor(manager *Manager) *UdevMonitor {
}
func (m *UdevMonitor) run(manager *Manager) {
conn := &netlink.UEventConn{}
if err := conn.Connect(netlink.UdevEvent); err != nil {
log.Errorf("Failed to connect to udev netlink: %v", err)
return
}
defer conn.Close()
matcher := &netlink.RuleDefinitions{
Rules: []netlink.RuleDefinition{
{Env: map[string]string{"SUBSYSTEM": "backlight"}},
@@ -48,6 +49,46 @@ func (m *UdevMonitor) run(manager *Manager) {
return
}
failures := 0
for {
if err := m.monitorLoop(manager, matcher); err != nil {
log.Errorf("Udev monitor error: %v", err)
}
select {
case <-m.stop:
return
default:
}
failures++
if failures > udevMaxRetries {
log.Errorf("Udev monitor exceeded %d retries, giving up", udevMaxRetries)
return
}
delay := min(udevBaseDelay*time.Duration(1<<(failures-1)), udevMaxDelay)
log.Infof("Udev monitor reconnecting in %v (attempt %d/%d)", delay, failures, udevMaxRetries)
select {
case <-m.stop:
return
case <-time.After(delay):
}
}
}
func (m *UdevMonitor) monitorLoop(manager *Manager, matcher *netlink.RuleDefinitions) error {
conn := &netlink.UEventConn{}
if err := conn.Connect(netlink.UdevEvent); err != nil {
return err
}
defer conn.Close()
if err := syscall.SetsockoptInt(conn.Fd, syscall.SOL_SOCKET, syscall.SO_RCVBUF, udevRecvBufSize); err != nil {
log.Warnf("Failed to set udev socket receive buffer: %v", err)
}
events := make(chan netlink.UEvent)
errs := make(chan error)
conn.Monitor(events, errs, matcher)
@@ -57,10 +98,9 @@ func (m *UdevMonitor) run(manager *Manager) {
for {
select {
case <-m.stop:
return
return nil
case err := <-errs:
log.Errorf("Udev monitor error: %v", err)
return
return err
case event := <-events:
m.handleEvent(manager, event)
}

View File

@@ -73,6 +73,7 @@ var dbusManager *serverDbus.Manager
var wlContext *wlcontext.SharedContext
var themeModeManager *thememode.Manager
var locationManager *location.Manager
var geoClientInstance geolocation.Client
const dbusClientID = "dms-dbus-client"
@@ -191,7 +192,7 @@ func InitializeFreedeskManager() error {
return nil
}
func InitializeWaylandManager(geoClient geolocation.Client) error {
func InitializeWaylandManager() error {
log.Info("Attempting to initialize Wayland gamma control...")
if wlContext == nil {
@@ -204,7 +205,7 @@ func InitializeWaylandManager(geoClient geolocation.Client) error {
}
config := wayland.DefaultConfig()
manager, err := wayland.NewManager(wlContext.Display(), geoClient, config)
manager, err := wayland.NewManager(wlContext.Display(), config)
if err != nil {
log.Errorf("Failed to initialize wayland manager: %v", err)
return err
@@ -385,8 +386,8 @@ func InitializeDbusManager() error {
return nil
}
func InitializeThemeModeManager(geoClient geolocation.Client) error {
manager := thememode.NewManager(geoClient)
func InitializeThemeModeManager() error {
manager := thememode.NewManager()
themeModeManager = manager
log.Info("Theme mode automation manager initialized")
@@ -1330,6 +1331,9 @@ func cleanupManagers() {
if locationManager != nil {
locationManager.Close()
}
if geoClientInstance != nil {
geoClientInstance.Close()
}
}
func Start(printDocs bool) error {
@@ -1545,9 +1549,6 @@ func Start(printDocs bool) error {
loginctlReady := make(chan struct{})
freedesktopReady := make(chan struct{})
geoClient := geolocation.NewClient()
defer geoClient.Close()
go func() {
defer close(loginctlReady)
if err := InitializeLoginctlManager(); err != nil {
@@ -1592,10 +1593,41 @@ func Start(printDocs bool) error {
}
}()
if err := InitializeWaylandManager(geoClient); err != nil {
if err := InitializeWaylandManager(); err != nil {
log.Warnf("Wayland manager unavailable: %v", err)
}
if err := InitializeThemeModeManager(); err != nil {
log.Warnf("Theme mode manager unavailable: %v", err)
} else {
notifyCapabilityChange()
go func() {
<-loginctlReady
if loginctlManager == nil {
return
}
themeModeManager.WatchLoginctl(loginctlManager)
}()
}
go func() {
geoClient := geolocation.NewClient()
geoClientInstance = geoClient
if waylandManager != nil {
waylandManager.SetGeoClient(geoClient)
}
if themeModeManager != nil {
themeModeManager.SetGeoClient(geoClient)
}
if err := InitializeLocationManager(geoClient); err != nil {
log.Warnf("Location manager unavailable: %v", err)
} else {
notifyCapabilityChange()
}
}()
go func() {
if err := InitializeBluezManager(); err != nil {
log.Warnf("Bluez manager unavailable: %v", err)
@@ -1624,25 +1656,6 @@ func Start(printDocs bool) error {
log.Debugf("WlrOutput manager unavailable: %v", err)
}
if err := InitializeThemeModeManager(geoClient); err != nil {
log.Warnf("Theme mode manager unavailable: %v", err)
} else {
notifyCapabilityChange()
go func() {
<-loginctlReady
if loginctlManager == nil {
return
}
themeModeManager.WatchLoginctl(loginctlManager)
}()
}
if err := InitializeLocationManager(geoClient); err != nil {
log.Warnf("Location manager unavailable: %v", err)
} else {
notifyCapabilityChange()
}
fatalErrChan := make(chan error, 1)
if wlrOutputManager != nil {
go func() {

View File

@@ -40,7 +40,7 @@ type Manager struct {
wg sync.WaitGroup
}
func NewManager(geoClient geolocation.Client) *Manager {
func NewManager() *Manager {
m := &Manager{
config: Config{
Enabled: false,
@@ -54,7 +54,6 @@ func NewManager(geoClient geolocation.Client) *Manager {
},
stopChan: make(chan struct{}),
updateTrigger: make(chan struct{}, 1),
geoClient: geoClient,
}
m.updateState(time.Now())
@@ -315,6 +314,10 @@ func (m *Manager) getConfig() Config {
return m.config
}
func (m *Manager) SetGeoClient(client geolocation.Client) {
m.geoClient = client
}
func (m *Manager) getLocation(config Config) (*float64, *float64) {
if config.Latitude != nil && config.Longitude != nil {
return config.Latitude, config.Longitude
@@ -322,6 +325,9 @@ func (m *Manager) getLocation(config Config) (*float64, *float64) {
if !config.UseIPLocation {
return nil, nil
}
if m.geoClient == nil {
return nil, nil
}
m.locationMutex.RLock()
if m.cachedIPLat != nil && m.cachedIPLon != nil {

View File

@@ -20,7 +20,7 @@ import (
const animKelvinStep = 25
func NewManager(display wlclient.WaylandDisplay, geoClient geolocation.Client, config Config) (*Manager, error) {
func NewManager(display wlclient.WaylandDisplay, config Config) (*Manager, error) {
if err := config.Validate(); err != nil {
return nil, err
}
@@ -41,7 +41,6 @@ func NewManager(display wlclient.WaylandDisplay, geoClient geolocation.Client, c
updateTrigger: make(chan struct{}, 1),
dirty: make(chan struct{}, 1),
dbusSignal: make(chan *dbus.Signal, 16),
geoClient: geoClient,
}
if err := m.setupRegistry(); err != nil {
@@ -422,6 +421,10 @@ func (m *Manager) recalcSchedule(now time.Time) {
}
}
func (m *Manager) SetGeoClient(client geolocation.Client) {
m.geoClient = client
}
func (m *Manager) getLocation() (*float64, *float64) {
m.configMutex.RLock()
config := m.config
@@ -430,27 +433,31 @@ func (m *Manager) getLocation() (*float64, *float64) {
if config.Latitude != nil && config.Longitude != nil {
return config.Latitude, config.Longitude
}
if config.UseIPLocation {
m.locationMutex.RLock()
if m.cachedIPLat != nil && m.cachedIPLon != nil {
lat, lon := m.cachedIPLat, m.cachedIPLon
m.locationMutex.RUnlock()
return lat, lon
}
m.locationMutex.RUnlock()
location, err := m.geoClient.GetLocation()
if err != nil {
return nil, nil
}
m.locationMutex.Lock()
m.cachedIPLat = &location.Latitude
m.cachedIPLon = &location.Longitude
m.locationMutex.Unlock()
return m.cachedIPLat, m.cachedIPLon
if !config.UseIPLocation {
return nil, nil
}
return nil, nil
if m.geoClient == nil {
return nil, nil
}
m.locationMutex.RLock()
if m.cachedIPLat != nil && m.cachedIPLon != nil {
lat, lon := m.cachedIPLat, m.cachedIPLon
m.locationMutex.RUnlock()
return lat, lon
}
m.locationMutex.RUnlock()
location, err := m.geoClient.GetLocation()
if err != nil {
return nil, nil
}
m.locationMutex.Lock()
m.cachedIPLat = &location.Latitude
m.cachedIPLon = &location.Longitude
m.locationMutex.Unlock()
return m.cachedIPLat, m.cachedIPLon
}
func (m *Manager) hasValidSchedule() bool {

View File

@@ -8,7 +8,6 @@ import (
"github.com/stretchr/testify/assert"
mocks_geolocation "github.com/AvengeMedia/DankMaterialShell/core/internal/mocks/geolocation"
mocks_wlclient "github.com/AvengeMedia/DankMaterialShell/core/internal/mocks/wlclient"
)
@@ -391,20 +390,18 @@ func TestNotifySubscribers_NonBlocking(t *testing.T) {
func TestNewManager_GetRegistryError(t *testing.T) {
mockDisplay := mocks_wlclient.NewMockWaylandDisplay(t)
mockGeoclient := mocks_geolocation.NewMockClient(t)
mockDisplay.EXPECT().Context().Return(nil)
mockDisplay.EXPECT().GetRegistry().Return(nil, errors.New("failed to get registry"))
config := DefaultConfig()
_, err := NewManager(mockDisplay, mockGeoclient, config)
_, err := NewManager(mockDisplay, config)
assert.Error(t, err)
assert.Contains(t, err.Error(), "get registry")
}
func TestNewManager_InvalidConfig(t *testing.T) {
mockDisplay := mocks_wlclient.NewMockWaylandDisplay(t)
mockGeoclient := mocks_geolocation.NewMockClient(t)
config := Config{
LowTemp: 500,
@@ -412,6 +409,6 @@ func TestNewManager_InvalidConfig(t *testing.T) {
Gamma: 1.0,
}
_, err := NewManager(mockDisplay, mockGeoclient, config)
_, err := NewManager(mockDisplay, config)
assert.Error(t, err)
}

View File

@@ -2,10 +2,10 @@ package wlcontext
import (
"fmt"
"golang.org/x/sys/unix"
"os"
"sync"
"golang.org/x/sys/unix"
"time"
"github.com/AvengeMedia/DankMaterialShell/core/internal/errdefs"
"github.com/AvengeMedia/DankMaterialShell/core/internal/log"
@@ -123,6 +123,9 @@ func (sc *SharedContext) eventDispatcher() {
{Fd: int32(sc.wakeR), Events: unix.POLLIN},
}
consecutiveErrors := 0
const maxConsecutiveErrors = 20
for {
sc.drainCmdQueue()
@@ -153,9 +156,19 @@ func (sc *SharedContext) eventDispatcher() {
}
if err := ctx.Dispatch(); err != nil && !os.IsTimeout(err) {
log.Errorf("Wayland connection error: %v", err)
return
consecutiveErrors++
log.Warnf("Wayland connection error (%d/%d): %v", consecutiveErrors, maxConsecutiveErrors, err)
if consecutiveErrors >= maxConsecutiveErrors {
log.Errorf("Fatal: Wayland connection unrecoverable after %d attempts. Exiting dispatcher.", maxConsecutiveErrors)
return
}
time.Sleep(100 * time.Millisecond * time.Duration(consecutiveErrors))
continue
}
consecutiveErrors = 0
}
}

View File

@@ -40,7 +40,7 @@ func (m Model) viewDeployingConfigs() string {
spinner := m.spinner.View()
status := m.styles.Normal.Render("Setting up configuration files...")
b.WriteString(fmt.Sprintf("%s %s", spinner, status))
fmt.Fprintf(&b, "%s %s", spinner, status)
b.WriteString("\n\n")
// Show progress information

View File

@@ -23,7 +23,7 @@ func (m Model) viewDetectingDeps() string {
spinner := m.spinner.View()
status := m.styles.Normal.Render("Scanning system for existing packages and configurations...")
b.WriteString(fmt.Sprintf("%s %s", spinner, status))
fmt.Fprintf(&b, "%s %s", spinner, status)
return b.String()
}

View File

@@ -52,7 +52,7 @@ func (m Model) viewInstallingPackages() string {
if !m.packageProgress.isComplete {
spinner := m.spinner.View()
status := m.styles.Normal.Render(m.packageProgress.step)
b.WriteString(fmt.Sprintf("%s %s", spinner, status))
fmt.Fprintf(&b, "%s %s", spinner, status)
b.WriteString("\n\n")
// Show progress bar
@@ -387,7 +387,7 @@ func (m Model) viewDebugLogs() string {
for i := startIdx; i < len(allLogs); i++ {
if allLogs[i] != "" {
b.WriteString(fmt.Sprintf("%d: %s\n", i, allLogs[i]))
fmt.Fprintf(&b, "%d: %s\n", i, allLogs[i])
}
}

View File

@@ -75,7 +75,7 @@ func (m Model) viewFingerprintAuth() string {
spinner := m.spinner.View()
status := m.styles.Normal.Render("Waiting for fingerprint...")
b.WriteString(fmt.Sprintf("%s %s", spinner, status))
fmt.Fprintf(&b, "%s %s", spinner, status)
}
return b.String()

View File

@@ -132,9 +132,9 @@ func (m Model) viewWelcome() string {
contentStyle = contentStyle.Bold(true)
}
b.WriteString(fmt.Sprintf(" %s %s\n",
fmt.Fprintf(&b, " %s %s\n",
prefixStyle.Render(prefix),
contentStyle.Render(content)))
contentStyle.Render(content))
}
b.WriteString("\n")
@@ -158,7 +158,7 @@ func (m Model) viewWelcome() string {
} else if m.isLoading {
spinner := m.spinner.View()
loading := m.styles.Normal.Render("Detecting system...")
b.WriteString(fmt.Sprintf("%s %s\n\n", spinner, loading))
fmt.Fprintf(&b, "%s %s\n\n", spinner, loading)
}
// Footer with better visual separation

View File

@@ -17,6 +17,25 @@
...
}:
let
goModVersion =
let
content = builtins.readFile ./core/go.mod;
lines = builtins.filter builtins.isString (builtins.split "\n" content);
goLines = builtins.filter (l: builtins.match "go [0-9]+\\..*" l != null) lines;
matched =
if goLines != [ ] then builtins.match "go ([0-9]+)\\.([0-9]+).*" (builtins.head goLines) else null;
in
if matched != null then
{
major = builtins.elemAt matched 0;
minor = builtins.elemAt matched 1;
}
else
{
major = "1";
minor = "25";
};
goForPkgs = pkgs: pkgs.${"go_${goModVersion.major}_${goModVersion.minor}"};
forEachSystem =
fn:
nixpkgs.lib.genAttrs [ "aarch64-darwin" "aarch64-linux" "x86_64-darwin" "x86_64-linux" ] (
@@ -76,7 +95,7 @@
{
extraQtPackages ? [ ],
}:
pkgs.buildGoModule (
(pkgs.buildGoModule.override { go = goForPkgs pkgs; }) (
let
rootSrc = ./.;
qtPackages = (qmlPkgs pkgs) ++ extraQtPackages;
@@ -187,7 +206,7 @@
buildInputs =
with pkgs;
[
go_1_25
(goForPkgs pkgs)
go-mockery_2
gopls
delve

View File

@@ -580,14 +580,7 @@ Singleton {
}
}
if (!newSettings[identifier]) {
newSettings[identifier] = {
"enabled": false,
"mode": "interval",
"interval": 300,
"time": "06:00"
};
}
newSettings[identifier] = getMonitorCyclingSettings(screenName);
newSettings[identifier].enabled = enabled;
monitorCyclingSettings = newSettings;
saveSettings();
@@ -618,14 +611,7 @@ Singleton {
}
}
if (!newSettings[identifier]) {
newSettings[identifier] = {
"enabled": false,
"mode": "interval",
"interval": 300,
"time": "06:00"
};
}
newSettings[identifier] = getMonitorCyclingSettings(screenName);
newSettings[identifier].mode = mode;
monitorCyclingSettings = newSettings;
saveSettings();
@@ -656,14 +642,7 @@ Singleton {
}
}
if (!newSettings[identifier]) {
newSettings[identifier] = {
"enabled": false,
"mode": "interval",
"interval": 300,
"time": "06:00"
};
}
newSettings[identifier] = getMonitorCyclingSettings(screenName);
newSettings[identifier].interval = interval;
monitorCyclingSettings = newSettings;
saveSettings();
@@ -694,14 +673,7 @@ Singleton {
}
}
if (!newSettings[identifier]) {
newSettings[identifier] = {
"enabled": false,
"mode": "interval",
"interval": 300,
"time": "06:00"
};
}
newSettings[identifier] = getMonitorCyclingSettings(screenName);
newSettings[identifier].time = time;
monitorCyclingSettings = newSettings;
saveSettings();
@@ -1218,7 +1190,7 @@ Singleton {
"time": "06:00"
};
var value = _findMonitorValue(monitorCyclingSettings, screenName);
return value !== undefined ? value : defaults;
return Object.assign({}, defaults, value !== undefined ? value : {});
}
FileView {

View File

@@ -477,6 +477,11 @@ Singleton {
property bool matugenTemplateEmacs: true
property bool matugenTemplateZed: true
property var matugenTemplateNeovimSettings: ({
"dark": { "baseTheme": "github_dark", "harmony": 0.5 },
"light": { "baseTheme": "github_light", "harmony": 0.5 }
})
property bool showDock: false
property bool dockAutoHide: false
property bool dockSmartAutoHide: false

View File

@@ -292,6 +292,13 @@ var SPEC = {
matugenTemplateEmacs: { def: true },
matugenTemplateZed: { def: true },
matugenTemplateNeovimSettings: {
def: {
dark: { baseTheme: "github_dark", harmony: 0.5 },
light: { baseTheme: "github_light", harmony: 0.5 }
}
},
showDock: { def: false },
dockAutoHide: { def: false },
dockSmartAutoHide: { def: false },

View File

@@ -2568,18 +2568,96 @@ Item {
onToggled: checked => SettingsData.set("matugenTemplateFoot", checked)
}
SettingsDivider {
visible: neovimThemeToggle.visible && neovimThemeToggle.checked
}
SettingsToggleRow {
id: neovimThemeToggle
tab: "theme"
tags: ["matugen", "neovim", "terminal", "template"]
settingKey: "matugenTemplateNeovim"
text: "neovim"
description: getTemplateDescription("nvim", I18n.tr("Requires lazy plugin manager", "neovim template description"))
description: getTemplateDescription("nvim", I18n.tr("Required plugin: ") + "https://github.com/AvengeMedia/base46")
descriptionColor: getTemplateDescriptionColor("nvim")
visible: SettingsData.runDmsMatugenTemplates
checked: SettingsData.matugenTemplateNeovim
onToggled: checked => SettingsData.set("matugenTemplateNeovim", checked)
}
SettingsDropdownRow {
text: I18n.tr("Dark mode base")
tab: "theme"
tags: ["matugen", "neovim", "terminal", "template"]
settingKey: "matugenTemplateNeovimSettings"
description: "Base to derive dark theme from"
visible: neovimThemeToggle.visible && neovimThemeToggle.checked
currentValue: SettingsData.matugenTemplateNeovimSettings?.dark?.baseTheme ?? "github_dark"
options: ["aquarium", "ashes", "aylin", "ayu_dark", "bearded-arc", "carbonfox", "catppuccin", "chadracula", "chadracula-evondev", "chadtain", "chocolate", "darcula-dark", "dark_horizon", "decay", "default-dark", "doomchad", "eldritch", "embark", "everblush", "everforest", "falcon", "flexoki", "flouromachine", "gatekeeper", "github_dark", "gruvbox", "gruvchad", "hiberbee", "horizon", "jabuti", "jellybeans", "kanagawa", "kanagawa-dragon", "material-darker", "material-deep-ocean", "melange", "midnight_breeze", "mito-laser", "monekai", "monochrome", "mountain", "neofusion", "nightfox", "nightlamp", "nightowl", "nord", "obsidian-ember", "oceanic-next", "onedark", "onenord", "oxocarbon", "palenight", "pastelDark", "pastelbeans", "penumbra_dark", "poimandres", "radium", "rosepine", "rxyhn", "scaryforest", "seoul256_dark", "solarized_dark", "solarized_osaka", "starlight", "sweetpastel", "tokyodark", "tokyonight", "tomorrow_night", "tundra", "vesper", "vscode_dark", "wombat", "yoru", "zenburn"]
enableFuzzySearch: true
onValueChanged: value => {
const settings = SettingsData.matugenTemplateNeovimSettings;
settings.dark.baseTheme = value;
SettingsData.set("matugenTemplateNeovimSettings", settings);
}
}
SettingsDropdownRow {
text: I18n.tr("Light mode base")
tab: "theme"
tags: ["matugen", "neovim", "terminal", "template"]
settingKey: "matugenTemplateNeovimSettings"
description: "Base to derive light theme from"
visible: neovimThemeToggle.visible && neovimThemeToggle.checked
currentValue: SettingsData.matugenTemplateNeovimSettings?.light?.baseTheme ?? "github_light"
options: ["ayu_light", "blossom_light", "catppuccin-latte", "default-light", "everforest_light", "flex-light", "flexoki-light", "github_light", "gruvbox_light", "material-lighter", "nano-light", "oceanic-light", "one_light", "onenord_light", "penumbra_light", "rosepine-dawn", "seoul256_light", "solarized_light", "sunrise_breeze", "vscode_light"]
enableFuzzySearch: true
onValueChanged: value => {
const settings = SettingsData.matugenTemplateNeovimSettings;
settings.light.baseTheme = value;
SettingsData.set("matugenTemplateNeovimSettings", settings);
}
}
SettingsSliderRow {
text: I18n.tr("Dark mode harmony")
tags: ["matugen", "neovim", "terminal", "template"]
settingKey: "matugenTemplateNeovimSettings"
description: "How much should the base dark theme be tinted"
visible: neovimThemeToggle.visible && neovimThemeToggle.checked
minimum: 0
maximum: 100
value: (SettingsData.matugenTemplateNeovimSettings?.dark?.harmony ?? 0.5) * 100
defaultValue: 50
onSliderValueChanged: value => {
const settings = SettingsData.matugenTemplateNeovimSettings;
settings.dark.harmony = value / 100;
SettingsData.set("matugenTemplateNeovimSettings", settings);
}
}
SettingsSliderRow {
text: I18n.tr("Light mode harmony")
tags: ["matugen", "neovim", "terminal", "template"]
settingKey: "matugenTemplateNeovimSettings"
description: "How much should the base light theme be tinted"
visible: neovimThemeToggle.visible && neovimThemeToggle.checked
minimum: 0
maximum: 100
value: (SettingsData.matugenTemplateNeovimSettings?.light?.harmony ?? 0.5) * 100
defaultValue: 50
onSliderValueChanged: value => {
const settings = SettingsData.matugenTemplateNeovimSettings;
settings.light.harmony = value / 100;
SettingsData.set("matugenTemplateNeovimSettings", settings);
}
}
SettingsDivider {
visible: neovimThemeToggle.visible && neovimThemeToggle.checked
}
SettingsToggleRow {
tab: "theme"
tags: ["matugen", "alacritty", "terminal", "template"]

View File

@@ -4,6 +4,7 @@ pragma ComponentBehavior: Bound
import QtCore
import QtQuick
import Quickshell
import Quickshell.Hyprland
import qs.Common
Singleton {

View File

@@ -1,3 +1,3 @@
[templates.dmsneovim]
input_path = 'SHELL_DIR/matugen/templates/neovim.lua'
output_path = 'CONFIG_DIR/nvim/lua/plugins/dankcolors.lua'
output_path = 'CONFIG_DIR/nvim/colors/dms.lua'

View File

@@ -1,40 +1,83 @@
return {
{
"RRethy/base16-nvim",
priority = 1000,
config = function()
require('base16-colorscheme').setup({
local present, base46 = pcall(require, "base46")
if not present or not base46._DMS_SUPPORT then
vim.notify(
"base46 plugin not found or incorrect, make sure to install AvengeMedia/base46",
vim.log.levels.ERROR,
{ title = "dms integration" }
)
return
end
base00 = '{{colors.background.dark.hex}}',
base01 = '{{colors.surface_container_low.dark.hex}}',
base02 = '{{colors.surface_container.dark.hex}}',
base03 = '{{dank16.color8.dark.hex}}',
base0B = '{{dank16.color3.dark.hex}}',
base04 = '{{dank16.color7.default.hex}}',
base05 = '{{dank16.color15.default.hex}}',
base06 = '{{dank16.color15.default.hex}}',
base07 = '{{dank16.color15.default.hex}}',
base08 = '{{dank16.color9.default.hex}}',
base09 = '{{dank16.color9.default.hex}}',
base0A = '{{dank16.color12.default.hex}}',
base0C = '{{dank16.color14.default.hex}}',
base0D = '{{dank16.color12.default.hex}}',
base0E = '{{dank16.color13.default.hex}}',
base0F = '{{dank16.color13.default.hex}}',
})
local config_home = vim.env.XDG_CONFIG_HOME
if config_home == nil or #config_home == 0 then
config_home = vim.fs.joinpath(vim.env.HOME, ".config")
end
local settings_file_path = vim.fs.joinpath(config_home, "DankMaterialShell", "settings.json")
local settings_file = io.open(settings_file_path, "r")
if settings_file == nil then
vim.notify(
"cannnot read dms settings file at '" .. settings_file_path .. "'",
vim.log.levels.ERROR,
{ title = "dms integration" }
)
return
end
local settings = vim.json.decode(settings_file:read("*a"))
settings_file:close()
local current_file_path = vim.fn.stdpath("config") .. "/lua/plugins/dankcolors.lua"
if not _G._matugen_theme_watcher then
local uv = vim.uv or vim.loop
_G._matugen_theme_watcher = uv.new_fs_event()
_G._matugen_theme_watcher:start(current_file_path, {}, vim.schedule_wrap(function()
local new_spec = dofile(current_file_path)
if new_spec and new_spec[1] and new_spec[1].config then
new_spec[1].config()
print("Theme reload")
end
end))
end
local function deepGet(t, k)
for _, s in ipairs(k) do
if type(t) ~= "table" then
return
end
}
}
t = t[s]
end
return t
end
local current_file_path = debug.getinfo(1, "S").source:sub(2)
local theme_base = deepGet(settings, { "matugenTemplateNeovimSettings", vim.o.background, "baseTheme" })
or ("github_" .. vim.o.background)
local harmony = deepGet(settings, { "matugenTemplateNeovimSettings", vim.o.background, "harmony" }) or 0.5
local theme_name = "dms"
if not _G._matugen_theme_watcher then
local uv = vim.uv or vim.loop
_G._matugen_theme_watcher = { uv.new_fs_event(), uv.new_fs_event(), reload_timer = uv.new_timer() }
local debounce_time = 100 -- ms
local function handler()
_G._matugen_theme_watcher.reload_timer:stop()
_G._matugen_theme_watcher.reload_timer:start(
debounce_time,
0,
vim.schedule_wrap(function()
base46.theme_tables[theme_name] = nil
if vim.g.colors_name == theme_name then
vim.cmd.colorscheme(theme_name)
vim.notify("Theme reload", vim.log.levels.INFO, { title = "dms integration" })
end
-- NOTE: contrary to what the documentation says, uv fs events usually do not manage to react to more than one edit.
-- I understand that this is not intended: some edit processes in a typical system (e.g. the one neovim uses with
-- multiple renames and changes) make things hard to follow for libuv. Therefore, a restart is the best option.
_G._matugen_theme_watcher[1]:stop()
_G._matugen_theme_watcher[2]:stop()
_G._matugen_theme_watcher[1]:start(current_file_path, {}, handler)
_G._matugen_theme_watcher[2]:start(settings_file_path, {}, handler)
end)
)
end
_G._matugen_theme_watcher[1]:start(current_file_path, {}, handler)
_G._matugen_theme_watcher[2]:start(settings_file_path, {}, handler)
end
if not base46.theme_tables[theme_name] or base46.theme_tables[theme_name].type ~= vim.o.background then
local builtin = vim.deepcopy(assert(base46.get_builtin_theme(theme_base)))
local harmonized = base46.theme_harmonize(builtin, "{{colors.source_color.default.hex}}", harmony)
harmonized = base46.theme_set_bg(harmonized, "{{colors.background.default.hex}}")
base46.theme_tables[theme_name] = harmonized
end
base46.load(theme_name)
vim.g.colors_name = theme_name

File diff suppressed because it is too large Load Diff

View File

@@ -2583,6 +2583,29 @@
"description": "Mouse pointer appearance",
"conditionKey": "isNiri"
},
{
"section": "matugenTemplateNeovimSettings",
"label": "Dark mode base",
"tabIndex": 10,
"category": "Theme & Colors",
"keywords": [
"appearance",
"base",
"colors",
"dark",
"dark mode",
"look",
"matugen",
"mode",
"neovim",
"night",
"scheme",
"style",
"template",
"terminal",
"theme"
]
},
{
"section": "modalDarkenBackground",
"label": "Darken Modal Background",
@@ -3948,20 +3971,17 @@
"keywords": [
"appearance",
"colors",
"lazy",
"look",
"manager",
"matugen",
"neovim",
"plugin",
"requires",
"required",
"scheme",
"style",
"template",
"terminal",
"theme"
],
"description": "Requires lazy plugin manager"
"description": "Required plugin: "
},
{
"section": "matugenTemplateNiri",
@@ -4138,18 +4158,14 @@
"authentication",
"biometric",
"enable",
"enrolled",
"fingerprint",
"fprint",
"lock",
"lockscreen",
"login",
"password",
"reader",
"screen",
"security"
],
"description": "Use fingerprint reader for lock screen authentication (requires enrolled fingerprints)"
]
},
{
"section": "loginctlLockIntegration",
@@ -4182,20 +4198,17 @@
"keywords": [
"authentication",
"enable",
"enrolled",
"fido",
"hardware",
"key",
"lock",
"lockscreen",
"login",
"password",
"screen",
"security",
"u2f",
"yubikey"
],
"description": "Use a FIDO2/U2F security key (e.g. YubiKey) for lock screen authentication (requires enrolled keys)"
]
},
{
"section": "lockDisplay",
@@ -4286,6 +4299,27 @@
],
"description": "Automatically lock the screen when DMS starts"
},
{
"section": "lockBeforeSuspend",
"label": "Lock before suspend",
"tabIndex": 11,
"category": "Lock Screen",
"keywords": [
"automatic",
"automatically",
"before",
"lock",
"login",
"password",
"prepares",
"screen",
"security",
"sleep",
"suspend",
"system"
],
"description": "Automatically lock the screen when the system prepares to suspend"
},
{
"section": "lockScreenNotificationMode",
"label": "Notification Display",
@@ -6288,27 +6322,6 @@
"icon": "schedule",
"description": "Gradually fade the screen before locking with a configurable grace period"
},
{
"section": "lockBeforeSuspend",
"label": "Lock before suspend",
"tabIndex": 21,
"category": "Power & Sleep",
"keywords": [
"automatically",
"before",
"energy",
"lock",
"power",
"prepares",
"screen",
"security",
"shutdown",
"sleep",
"suspend",
"system"
],
"description": "Automatically lock the screen when the system prepares to suspend"
},
{
"section": "fadeToLockGracePeriod",
"label": "Lock fade grace period",

View File

@@ -1518,6 +1518,13 @@
"reference": "",
"comment": ""
},
{
"term": "Available.",
"translation": "",
"context": "",
"reference": "",
"comment": ""
},
{
"term": "BSSID",
"translation": "",
@@ -3653,6 +3660,20 @@
"reference": "",
"comment": ""
},
{
"term": "Dark mode base",
"translation": "",
"context": "",
"reference": "",
"comment": ""
},
{
"term": "Dark mode harmony",
"translation": "",
"context": "",
"reference": "",
"comment": ""
},
{
"term": "Darken Modal Background",
"translation": "",
@@ -4003,13 +4024,6 @@
"reference": "",
"comment": ""
},
{
"term": "Disabled.",
"translation": "",
"context": "",
"reference": "",
"comment": ""
},
{
"term": "Disabling WiFi...",
"translation": "",
@@ -4647,6 +4661,76 @@
"reference": "",
"comment": ""
},
{
"term": "Enabled, but fingerprint availability could not be confirmed.",
"translation": "",
"context": "",
"reference": "",
"comment": ""
},
{
"term": "Enabled, but no fingerprint reader was detected.",
"translation": "",
"context": "",
"reference": "",
"comment": ""
},
{
"term": "Enabled, but no prints are enrolled yet. Enroll fingerprints and run Sync.",
"translation": "",
"context": "",
"reference": "",
"comment": ""
},
{
"term": "Enabled, but no prints are enrolled yet. Enroll fingerprints to use it.",
"translation": "",
"context": "",
"reference": "",
"comment": ""
},
{
"term": "Enabled, but no registered security key was found yet. Register a key and run Sync.",
"translation": "",
"context": "",
"reference": "",
"comment": ""
},
{
"term": "Enabled, but no registered security key was found yet. Register a key or update your U2F config.",
"translation": "",
"context": "",
"reference": "",
"comment": ""
},
{
"term": "Enabled, but security-key availability could not be confirmed.",
"translation": "",
"context": "",
"reference": "",
"comment": ""
},
{
"term": "Enabled. PAM already provides fingerprint auth.",
"translation": "",
"context": "",
"reference": "",
"comment": ""
},
{
"term": "Enabled. PAM already provides security-key auth.",
"translation": "",
"context": "",
"reference": "",
"comment": ""
},
{
"term": "Enabled. PAM provides fingerprint auth, but no prints are enrolled yet.",
"translation": "",
"context": "",
"reference": "",
"comment": ""
},
{
"term": "Enabling WiFi...",
"translation": "",
@@ -5529,6 +5613,27 @@
"reference": "",
"comment": ""
},
{
"term": "Fingerprint availability could not be confirmed.",
"translation": "",
"context": "",
"reference": "",
"comment": ""
},
{
"term": "Fingerprint reader detected, but no prints are enrolled yet. You can enable this now and enroll later.",
"translation": "",
"context": "",
"reference": "",
"comment": ""
},
{
"term": "Fingerprint reader detected, but no prints are enrolled yet. You can enable this now and run Sync later.",
"translation": "",
"context": "",
"reference": "",
"comment": ""
},
{
"term": "Finish",
"translation": "",
@@ -5641,6 +5746,13 @@
"reference": "",
"comment": ""
},
{
"term": "Focused Monitor Only",
"translation": "",
"context": "",
"reference": "",
"comment": ""
},
{
"term": "Focused Window",
"translation": "",
@@ -5648,6 +5760,13 @@
"reference": "",
"comment": ""
},
{
"term": "Focused monitor only",
"translation": "",
"context": "",
"reference": "",
"comment": ""
},
{
"term": "Fog",
"translation": "",
@@ -6425,6 +6544,20 @@
"reference": "",
"comment": ""
},
{
"term": "Highlight Active Workspace App",
"translation": "",
"context": "",
"reference": "",
"comment": ""
},
{
"term": "Highlight the currently focused app inside workspace indicators",
"translation": "",
"context": "",
"reference": "",
"comment": ""
},
{
"term": "History",
"translation": "",
@@ -7321,6 +7454,20 @@
"reference": "",
"comment": ""
},
{
"term": "Light mode base",
"translation": "",
"context": "",
"reference": "",
"comment": ""
},
{
"term": "Light mode harmony",
"translation": "",
"context": "",
"reference": "",
"comment": ""
},
{
"term": "Line",
"translation": "",
@@ -8826,6 +8973,13 @@
"reference": "",
"comment": ""
},
{
"term": "No fingerprint reader detected.",
"translation": "",
"context": "",
"reference": "",
"comment": ""
},
{
"term": "No folders found",
"translation": "",
@@ -9121,14 +9275,28 @@
"comment": ""
},
{
"term": "Not available — install fprintd and enroll fingerprints.",
"term": "Not available — install fprintd and pam_fprintd, or configure greetd PAM.",
"translation": "",
"context": "",
"reference": "",
"comment": ""
},
{
"term": "Not available — install pam_u2f and enroll keys.",
"term": "Not available — install fprintd and pam_fprintd.",
"translation": "",
"context": "",
"reference": "",
"comment": ""
},
{
"term": "Not available — install or configure pam_u2f, or configure greetd PAM.",
"translation": "",
"context": "",
"reference": "",
"comment": ""
},
{
"term": "Not available — install or configure pam_u2f.",
"translation": "",
"context": "",
"reference": "",
@@ -9148,13 +9316,6 @@
"reference": "",
"comment": ""
},
{
"term": "Not enrolled",
"translation": "",
"context": "fingerprint not detected status | security key not detected status",
"reference": "",
"comment": ""
},
{
"term": "Not paired",
"translation": "",
@@ -9394,7 +9555,7 @@
"comment": ""
},
{
"term": "Only off for DMS-managed PAM lines. If greetd includes system-auth/common-auth/password-auth with pam_fprintd, fingerprint still stays enabled.",
"term": "Only affects DMS-managed PAM. If greetd already includes pam_fprintd, fingerprint stays enabled.",
"translation": "",
"context": "",
"reference": "",
@@ -9715,6 +9876,41 @@
"reference": "",
"comment": ""
},
{
"term": "PAM already provides fingerprint auth. Enable this to show it at login.",
"translation": "",
"context": "",
"reference": "",
"comment": ""
},
{
"term": "PAM already provides security-key auth. Enable this to show it at login.",
"translation": "",
"context": "",
"reference": "",
"comment": ""
},
{
"term": "PAM provides fingerprint auth, but availability could not be confirmed.",
"translation": "",
"context": "",
"reference": "",
"comment": ""
},
{
"term": "PAM provides fingerprint auth, but no prints are enrolled yet.",
"translation": "",
"context": "",
"reference": "",
"comment": ""
},
{
"term": "PAM provides fingerprint auth, but no reader was detected.",
"translation": "",
"context": "",
"reference": "",
"comment": ""
},
{
"term": "PIN",
"translation": "",
@@ -10940,6 +11136,13 @@
"reference": "",
"comment": ""
},
{
"term": "Required plugin: ",
"translation": "",
"context": "",
"reference": "",
"comment": ""
},
{
"term": "Requires %1",
"translation": "",
@@ -10968,13 +11171,6 @@
"reference": "",
"comment": ""
},
{
"term": "Requires lazy plugin manager",
"translation": "",
"context": "neovim template description",
"reference": "",
"comment": ""
},
{
"term": "Requires night mode support",
"translation": "",
@@ -11052,6 +11248,13 @@
"reference": "",
"comment": ""
},
{
"term": "Restore Special Workspace Windows",
"translation": "",
"context": "",
"reference": "",
"comment": ""
},
{
"term": "Resume",
"translation": "",
@@ -11640,6 +11843,20 @@
"reference": "",
"comment": ""
},
{
"term": "Security-key availability could not be confirmed.",
"translation": "",
"context": "",
"reference": "",
"comment": ""
},
{
"term": "Security-key support was detected, but no registered key was found yet. You can enable this now and register one later.",
"translation": "",
"context": "",
"reference": "",
"comment": ""
},
{
"term": "Select",
"translation": "",
@@ -12585,6 +12802,20 @@
"reference": "",
"comment": ""
},
{
"term": "Show notification popups only on the currently focused monitor",
"translation": "",
"context": "",
"reference": "",
"comment": ""
},
{
"term": "Show notifications only on the currently focused monitor",
"translation": "",
"context": "",
"reference": "",
"comment": ""
},
{
"term": "Show on Last Display",
"translation": "",
@@ -14307,13 +14538,6 @@
"reference": "",
"comment": ""
},
{
"term": "Use a FIDO2/U2F security key (e.g. YubiKey) for lock screen authentication (requires enrolled keys)",
"translation": "",
"context": "lock screen U2F security key setting",
"reference": "",
"comment": ""
},
{
"term": "Use a custom image for the login screen, or leave empty to use your desktop wallpaper.",
"translation": "",
@@ -14328,6 +14552,13 @@
"reference": "",
"comment": ""
},
{
"term": "Use a security key for lock screen authentication.",
"translation": "",
"context": "lock screen U2F security key setting",
"reference": "",
"comment": ""
},
{
"term": "Use an external wallpaper manager like swww, hyprpaper, or swaybg.",
"translation": "",
@@ -14392,7 +14623,7 @@
"comment": ""
},
{
"term": "Use fingerprint reader for lock screen authentication (requires enrolled fingerprints)",
"term": "Use fingerprint authentication for the lock screen.",
"translation": "",
"context": "",
"reference": "",
@@ -14832,6 +15063,13 @@
"reference": "",
"comment": ""
},
{
"term": "When clicking a dock window in a Hyprland special workspace, bring that special workspace back before focusing the window",
"translation": "",
"context": "",
"reference": "",
"comment": ""
},
{
"term": "When enabled, apps are sorted alphabetically. When disabled, apps are sorted by usage frequency.",
"translation": "",