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

core: mock wayland context for tests & add i18n guidance to CONTRIBUTING

This commit is contained in:
bbedward
2025-12-11 14:50:02 -05:00
parent 9cac93b724
commit 6d66f93565
25 changed files with 1145 additions and 130 deletions

View File

@@ -14,6 +14,7 @@ import (
"github.com/AvengeMedia/DankMaterialShell/core/internal/clipboard"
"github.com/AvengeMedia/DankMaterialShell/core/internal/log"
"github.com/AvengeMedia/DankMaterialShell/core/internal/server/models"
"github.com/spf13/cobra"
)
@@ -281,10 +282,9 @@ func runCommand(args []string, stdin []byte) {
}
func runClipHistory(cmd *cobra.Command, args []string) {
req := map[string]any{
"id": 1,
"method": "clipboard.getHistory",
"params": map[string]any{},
req := models.Request{
ID: 1,
Method: "clipboard.getHistory",
}
resp, err := sendServerRequest(req)
@@ -305,7 +305,7 @@ func runClipHistory(cmd *cobra.Command, args []string) {
return
}
historyList, ok := resp.Result.([]any)
historyList, ok := (*resp.Result).([]any)
if !ok {
log.Fatal("Invalid response format")
}
@@ -353,10 +353,10 @@ func runClipGet(cmd *cobra.Command, args []string) {
}
if clipGetCopy {
req := map[string]any{
"id": 1,
"method": "clipboard.copyEntry",
"params": map[string]any{
req := models.Request{
ID: 1,
Method: "clipboard.copyEntry",
Params: map[string]any{
"id": id,
},
}
@@ -374,10 +374,10 @@ func runClipGet(cmd *cobra.Command, args []string) {
return
}
req := map[string]any{
"id": 1,
"method": "clipboard.getEntry",
"params": map[string]any{
req := models.Request{
ID: 1,
Method: "clipboard.getEntry",
Params: map[string]any{
"id": id,
},
}
@@ -395,7 +395,7 @@ func runClipGet(cmd *cobra.Command, args []string) {
log.Fatal("Entry not found")
}
entry, ok := resp.Result.(map[string]any)
entry, ok := (*resp.Result).(map[string]any)
if !ok {
log.Fatal("Invalid response format")
}
@@ -420,10 +420,10 @@ func runClipDelete(cmd *cobra.Command, args []string) {
log.Fatalf("Invalid ID: %v", err)
}
req := map[string]any{
"id": 1,
"method": "clipboard.deleteEntry",
"params": map[string]any{
req := models.Request{
ID: 1,
Method: "clipboard.deleteEntry",
Params: map[string]any{
"id": id,
},
}
@@ -441,10 +441,9 @@ func runClipDelete(cmd *cobra.Command, args []string) {
}
func runClipClear(cmd *cobra.Command, args []string) {
req := map[string]any{
"id": 1,
"method": "clipboard.clearHistory",
"params": map[string]any{},
req := models.Request{
ID: 1,
Method: "clipboard.clearHistory",
}
resp, err := sendServerRequest(req)
@@ -477,10 +476,10 @@ func runClipSearch(cmd *cobra.Command, args []string) {
params["isImage"] = false
}
req := map[string]any{
"id": 1,
"method": "clipboard.search",
"params": params,
req := models.Request{
ID: 1,
Method: "clipboard.search",
Params: params,
}
resp, err := sendServerRequest(req)
@@ -492,7 +491,11 @@ func runClipSearch(cmd *cobra.Command, args []string) {
log.Fatalf("Error: %s", resp.Error)
}
result, ok := resp.Result.(map[string]any)
if resp.Result == nil {
log.Fatal("No results")
}
result, ok := (*resp.Result).(map[string]any)
if !ok {
log.Fatal("Invalid response format")
}
@@ -540,10 +543,9 @@ func runClipSearch(cmd *cobra.Command, args []string) {
}
func runClipConfigGet(cmd *cobra.Command, args []string) {
req := map[string]any{
"id": 1,
"method": "clipboard.getConfig",
"params": map[string]any{},
req := models.Request{
ID: 1,
Method: "clipboard.getConfig",
}
resp, err := sendServerRequest(req)
@@ -555,7 +557,11 @@ func runClipConfigGet(cmd *cobra.Command, args []string) {
log.Fatalf("Error: %s", resp.Error)
}
cfg, ok := resp.Result.(map[string]any)
if resp.Result == nil {
log.Fatal("No config returned")
}
cfg, ok := (*resp.Result).(map[string]any)
if !ok {
log.Fatal("Invalid response format")
}
@@ -603,10 +609,10 @@ func runClipConfigSet(cmd *cobra.Command, args []string) {
return
}
req := map[string]any{
"id": 1,
"method": "clipboard.setConfig",
"params": params,
req := models.Request{
ID: 1,
Method: "clipboard.setConfig",
Params: params,
}
resp, err := sendServerRequest(req)

View File

@@ -2,15 +2,12 @@ package main
import (
"context"
"encoding/json"
"fmt"
"net"
"os"
"time"
"github.com/AvengeMedia/DankMaterialShell/core/internal/log"
"github.com/AvengeMedia/DankMaterialShell/core/internal/matugen"
"github.com/AvengeMedia/DankMaterialShell/core/internal/server"
"github.com/AvengeMedia/DankMaterialShell/core/internal/server/models"
"github.com/spf13/cobra"
)
@@ -100,33 +97,10 @@ func runMatugenQueue(cmd *cobra.Command, args []string) {
wait, _ := cmd.Flags().GetBool("wait")
timeout, _ := cmd.Flags().GetDuration("timeout")
socketPath := os.Getenv("DMS_SOCKET")
if socketPath == "" {
var err error
socketPath, err = server.FindSocket()
if err != nil {
log.Info("No socket available, running synchronously")
if err := matugen.Run(opts); err != nil {
log.Fatalf("Theme generation failed: %v", err)
}
return
}
}
conn, err := net.Dial("unix", socketPath)
if err != nil {
log.Info("Socket connection failed, running synchronously")
if err := matugen.Run(opts); err != nil {
log.Fatalf("Theme generation failed: %v", err)
}
return
}
defer conn.Close()
request := map[string]any{
"id": 1,
"method": "matugen.queue",
"params": map[string]any{
request := models.Request{
ID: 1,
Method: "matugen.queue",
Params: map[string]any{
"stateDir": opts.StateDir,
"shellDir": opts.ShellDir,
"configDir": opts.ConfigDir,
@@ -144,11 +118,14 @@ func runMatugenQueue(cmd *cobra.Command, args []string) {
},
}
if err := json.NewEncoder(conn).Encode(request); err != nil {
log.Fatalf("Failed to send request: %v", err)
}
if !wait {
if err := sendServerRequestFireAndForget(request); err != nil {
log.Info("Server unavailable, running synchronously")
if err := matugen.Run(opts); err != nil {
log.Fatalf("Theme generation failed: %v", err)
}
return
}
fmt.Println("Theme generation queued")
return
}
@@ -158,17 +135,18 @@ func runMatugenQueue(cmd *cobra.Command, args []string) {
resultCh := make(chan error, 1)
go func() {
var response struct {
ID int `json:"id"`
Result any `json:"result"`
Error string `json:"error"`
}
if err := json.NewDecoder(conn).Decode(&response); err != nil {
resultCh <- fmt.Errorf("failed to read response: %w", err)
resp, ok := tryServerRequest(request)
if !ok {
log.Info("Server unavailable, running synchronously")
if err := matugen.Run(opts); err != nil {
resultCh <- err
return
}
resultCh <- nil
return
}
if response.Error != "" {
resultCh <- fmt.Errorf("server error: %s", response.Error)
if resp.Error != "" {
resultCh <- fmt.Errorf("server error: %s", resp.Error)
return
}
resultCh <- nil

View File

@@ -1,17 +1,14 @@
package main
import (
"encoding/json"
"fmt"
"mime"
"net"
"net/url"
"os"
"path/filepath"
"strings"
"github.com/AvengeMedia/DankMaterialShell/core/internal/log"
"github.com/AvengeMedia/DankMaterialShell/core/internal/server"
"github.com/AvengeMedia/DankMaterialShell/core/internal/server/models"
"github.com/spf13/cobra"
)
@@ -93,32 +90,6 @@ func mimeTypeToCategories(mimeType string) []string {
}
func runOpen(target string) {
socketPath, err := server.FindSocket()
if err != nil {
log.Warnf("DMS socket not found: %v", err)
fmt.Println("DMS is not running. Please start DMS first.")
os.Exit(1)
}
conn, err := net.Dial("unix", socketPath)
if err != nil {
log.Warnf("DMS socket connection failed: %v", err)
fmt.Println("DMS is not running. Please start DMS first.")
os.Exit(1)
}
defer conn.Close()
buf := make([]byte, 1)
for {
_, err := conn.Read(buf)
if err != nil {
return
}
if buf[0] == '\n' {
break
}
}
// Parse file:// URIs to extract the actual file path
actualTarget := target
detectedMimeType := openMimeType
@@ -219,8 +190,9 @@ func runOpen(target string) {
log.Infof("Sending request - Method: %s, Params: %+v", method, params)
if err := json.NewEncoder(conn).Encode(req); err != nil {
log.Fatalf("Failed to send request: %v", err)
if err := sendServerRequestFireAndForget(req); err != nil {
fmt.Println("DMS is not running. Please start DMS first.")
os.Exit(1)
}
log.Infof("Request sent successfully")

View File

@@ -9,15 +9,10 @@ import (
"path/filepath"
"github.com/AvengeMedia/DankMaterialShell/core/internal/server"
"github.com/AvengeMedia/DankMaterialShell/core/internal/server/models"
)
type serverResponse struct {
ID int `json:"id,omitempty"`
Result any `json:"result,omitempty"`
Error string `json:"error,omitempty"`
}
func sendServerRequest(req map[string]any) (*serverResponse, error) {
func sendServerRequest(req models.Request) (*models.Response[any], error) {
socketPath := getServerSocketPath()
conn, err := net.Dial("unix", socketPath)
@@ -46,7 +41,7 @@ func sendServerRequest(req map[string]any) (*serverResponse, error) {
return nil, fmt.Errorf("failed to read response")
}
var resp serverResponse
var resp models.Response[any]
if err := json.Unmarshal(scanner.Bytes(), &resp); err != nil {
return nil, fmt.Errorf("failed to unmarshal response: %w", err)
}
@@ -54,6 +49,46 @@ func sendServerRequest(req map[string]any) (*serverResponse, error) {
return &resp, nil
}
// sendServerRequestFireAndForget sends a request without waiting for a response.
// Useful for commands that trigger UI or async operations.
func sendServerRequestFireAndForget(req models.Request) error {
socketPath := getServerSocketPath()
conn, err := net.Dial("unix", socketPath)
if err != nil {
return fmt.Errorf("failed to connect to server (is it running?): %w", err)
}
defer conn.Close()
scanner := bufio.NewScanner(conn)
scanner.Scan() // discard initial capabilities message
reqData, err := json.Marshal(req)
if err != nil {
return fmt.Errorf("failed to marshal request: %w", err)
}
if _, err := conn.Write(reqData); err != nil {
return fmt.Errorf("failed to write request: %w", err)
}
if _, err := conn.Write([]byte("\n")); err != nil {
return fmt.Errorf("failed to write newline: %w", err)
}
return nil
}
// tryServerRequest attempts to send a request but returns false if server unavailable.
// Does not log errors - caller can decide what to do on failure.
func tryServerRequest(req models.Request) (*models.Response[any], bool) {
resp, err := sendServerRequest(req)
if err != nil {
return nil, false
}
return resp, true
}
func getServerSocketPath() string {
runtimeDir := os.Getenv("XDG_RUNTIME_DIR")
if runtimeDir == "" {