Have got text transformations working
This commit is contained in:
		
							parent
							
								
									9f2fa96b92
								
							
						
					
					
						commit
						41daf7cfc9
					
				
							
								
								
									
										33
									
								
								app.go
									
									
									
									
									
								
							
							
						
						
									
										33
									
								
								app.go
									
									
									
									
									
								
							| 
						 | 
					@ -2,7 +2,10 @@ package main
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"context"
 | 
						"context"
 | 
				
			||||||
	"fmt"
 | 
						"log"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"github.com/wailsapp/wails/v2/pkg/runtime"
 | 
				
			||||||
 | 
						"lmika.dev/pkg/modash/moslice"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// App struct
 | 
					// App struct
 | 
				
			||||||
| 
						 | 
					@ -22,6 +25,30 @@ func (a *App) startup(ctx context.Context) {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Greet returns a greeting for the given name
 | 
					// Greet returns a greeting for the given name
 | 
				
			||||||
func (a *App) Greet(name string) string {
 | 
					func (a *App) ProcessText(req ProcessTextRequest) {
 | 
				
			||||||
	return fmt.Sprintf("Hello %s, It's show time!", name)
 | 
						filter, ok := TextFilters[req.Action]
 | 
				
			||||||
 | 
						if !ok {
 | 
				
			||||||
 | 
							log.Printf("Unknown filter: [%s]", req.Action)
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						resp, err := moslice.MapWithError(req.Input, func(span TextSpan) (TextSpan, error) {
 | 
				
			||||||
 | 
							outStr, err := filter(span.Text)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								return TextSpan{}, err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return TextSpan{
 | 
				
			||||||
 | 
								Text: outStr,
 | 
				
			||||||
 | 
								Pos:  span.Pos,
 | 
				
			||||||
 | 
								Len:  span.Len,
 | 
				
			||||||
 | 
							}, nil
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							log.Printf("Error running filter: %s", err)
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						runtime.EventsEmit(a.ctx, "process-text-response", ProcessTextResponse{
 | 
				
			||||||
 | 
							Output: resp,
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -15,10 +15,8 @@
 | 
				
			||||||
            data-action="keyup.enter->commands#runCommand keydown.esc->commands#dismissDialog keyup->commands#handleKeyup">
 | 
					            data-action="keyup.enter->commands#runCommand keydown.esc->commands#dismissDialog keyup->commands#handleKeyup">
 | 
				
			||||||
      </div>
 | 
					      </div>
 | 
				
			||||||
      <select multiple class="command-options" data-commands-target="commandSelect">
 | 
					      <select multiple class="command-options" data-commands-target="commandSelect">
 | 
				
			||||||
        <option value="double"><span class="option-label">Double quotes</span></option>
 | 
					        <option value="unquote"><span class="option-label">Unquote</span></option>
 | 
				
			||||||
        <option value="single"><span class="option-label">Single</span></option>
 | 
					        <option value="format-json"><span class="option-label">Format JSON</span></option>
 | 
				
			||||||
        <option value="backtick"><span class="option-label">Backtick quotes</span></option>
 | 
					 | 
				
			||||||
        <option value="none"><span class="option-label">None</span></option>
 | 
					 | 
				
			||||||
      </select>
 | 
					      </select>
 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
  </dialog>
 | 
					  </dialog>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,5 +1,6 @@
 | 
				
			||||||
.cm-editor {
 | 
					.cm-editor {
 | 
				
			||||||
    height: 100%;
 | 
					    height: 100%;
 | 
				
			||||||
 | 
					    font-size: 1.1em;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
dialog#command-dialog {
 | 
					dialog#command-dialog {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,6 +1,8 @@
 | 
				
			||||||
import { Controller } from "@hotwired/stimulus"
 | 
					import { Controller } from "@hotwired/stimulus"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export default class extends Controller {
 | 
					import { textProcessor } from "../services.js";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export class CommandsController extends Controller {
 | 
				
			||||||
    static targets = [
 | 
					    static targets = [
 | 
				
			||||||
        "commandInput",
 | 
					        "commandInput",
 | 
				
			||||||
        "commandSelect",
 | 
					        "commandSelect",
 | 
				
			||||||
| 
						 | 
					@ -30,7 +32,7 @@ export default class extends Controller {
 | 
				
			||||||
    runCommand(ev) {
 | 
					    runCommand(ev) {
 | 
				
			||||||
        ev.preventDefault();
 | 
					        ev.preventDefault();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        console.log("Do this: " + this.commandSelectTarget.value);
 | 
					        textProcessor.runTextCommand(this.commandSelectTarget.value);
 | 
				
			||||||
        this.element.close();
 | 
					        this.element.close();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -5,7 +5,8 @@ import {EditorView, basicSetup} from "codemirror";
 | 
				
			||||||
import {keymap} from "@codemirror/view";
 | 
					import {keymap} from "@codemirror/view";
 | 
				
			||||||
import { Application } from "@hotwired/stimulus";
 | 
					import { Application } from "@hotwired/stimulus";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import CommandsController from "./controllers/commands_controller.js";
 | 
					import { textProcessor } from "./services.js";
 | 
				
			||||||
 | 
					import {CommandsController} from "./controllers/commands_controller.js";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const view = new EditorView({
 | 
					const view = new EditorView({
 | 
				
			||||||
    parent: document.querySelector("#app"),
 | 
					    parent: document.querySelector("#app"),
 | 
				
			||||||
| 
						 | 
					@ -27,4 +28,6 @@ const view = new EditorView({
 | 
				
			||||||
window.Stimulus = Application.start()
 | 
					window.Stimulus = Application.start()
 | 
				
			||||||
Stimulus.register("commands", CommandsController);
 | 
					Stimulus.register("commands", CommandsController);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					textProcessor.setCodeMirrorEditor(view);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
view.focus();
 | 
					view.focus();
 | 
				
			||||||
							
								
								
									
										31
									
								
								frontend/src/services.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								frontend/src/services.js
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,31 @@
 | 
				
			||||||
 | 
					import {ProcessText} from "../wailsjs/go/main/App";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class TextProcessor {
 | 
				
			||||||
 | 
					    setCodeMirrorEditor(editor) {
 | 
				
			||||||
 | 
					        this._editor = editor;
 | 
				
			||||||
 | 
					        window.runtime.EventsOn("process-text-response", (data) => {
 | 
				
			||||||
 | 
					            const changes = data.output.map(span => ({
 | 
				
			||||||
 | 
					                from: span.pos,
 | 
				
			||||||
 | 
					                to: span.pos + span.len,
 | 
				
			||||||
 | 
					                insert: span.text,
 | 
				
			||||||
 | 
					            }));
 | 
				
			||||||
 | 
					            this._editor.dispatch({ changes: changes });
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    runTextCommand(command) {
 | 
				
			||||||
 | 
					        if (this._editor === undefined) {
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        ProcessText({
 | 
				
			||||||
 | 
					            action: command,
 | 
				
			||||||
 | 
					            input: [
 | 
				
			||||||
 | 
					                {text:  this._editor.state.doc.toString(), pos: 0, len: this._editor.state.doc.length}
 | 
				
			||||||
 | 
					            ],
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const textProcessor = new TextProcessor();
 | 
				
			||||||
							
								
								
									
										3
									
								
								frontend/wailsjs/go/main/App.d.ts
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								frontend/wailsjs/go/main/App.d.ts
									
									
									
									
										vendored
									
									
								
							| 
						 | 
					@ -1,4 +1,5 @@
 | 
				
			||||||
// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
 | 
					// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
 | 
				
			||||||
// This file is automatically generated. DO NOT EDIT
 | 
					// This file is automatically generated. DO NOT EDIT
 | 
				
			||||||
 | 
					import {main} from '../models';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export function Greet(arg1:string):Promise<string>;
 | 
					export function ProcessText(arg1:main.ProcessTextRequest):Promise<void>;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2,6 +2,6 @@
 | 
				
			||||||
// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
 | 
					// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
 | 
				
			||||||
// This file is automatically generated. DO NOT EDIT
 | 
					// This file is automatically generated. DO NOT EDIT
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export function Greet(arg1) {
 | 
					export function ProcessText(arg1) {
 | 
				
			||||||
  return window['go']['main']['App']['Greet'](arg1);
 | 
					  return window['go']['main']['App']['ProcessText'](arg1);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										53
									
								
								frontend/wailsjs/go/models.ts
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										53
									
								
								frontend/wailsjs/go/models.ts
									
									
									
									
									
										Executable file
									
								
							| 
						 | 
					@ -0,0 +1,53 @@
 | 
				
			||||||
 | 
					export namespace main {
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						export class TextSpan {
 | 
				
			||||||
 | 
						    text: string;
 | 
				
			||||||
 | 
						    pos: number;
 | 
				
			||||||
 | 
						    len: number;
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						    static createFrom(source: any = {}) {
 | 
				
			||||||
 | 
						        return new TextSpan(source);
 | 
				
			||||||
 | 
						    }
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						    constructor(source: any = {}) {
 | 
				
			||||||
 | 
						        if ('string' === typeof source) source = JSON.parse(source);
 | 
				
			||||||
 | 
						        this.text = source["text"];
 | 
				
			||||||
 | 
						        this.pos = source["pos"];
 | 
				
			||||||
 | 
						        this.len = source["len"];
 | 
				
			||||||
 | 
						    }
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						export class ProcessTextRequest {
 | 
				
			||||||
 | 
						    action: string;
 | 
				
			||||||
 | 
						    input: TextSpan[];
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						    static createFrom(source: any = {}) {
 | 
				
			||||||
 | 
						        return new ProcessTextRequest(source);
 | 
				
			||||||
 | 
						    }
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						    constructor(source: any = {}) {
 | 
				
			||||||
 | 
						        if ('string' === typeof source) source = JSON.parse(source);
 | 
				
			||||||
 | 
						        this.action = source["action"];
 | 
				
			||||||
 | 
						        this.input = this.convertValues(source["input"], TextSpan);
 | 
				
			||||||
 | 
						    }
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
							convertValues(a: any, classs: any, asMap: boolean = false): any {
 | 
				
			||||||
 | 
							    if (!a) {
 | 
				
			||||||
 | 
							        return a;
 | 
				
			||||||
 | 
							    }
 | 
				
			||||||
 | 
							    if (a.slice && a.map) {
 | 
				
			||||||
 | 
							        return (a as any[]).map(elem => this.convertValues(elem, classs));
 | 
				
			||||||
 | 
							    } else if ("object" === typeof a) {
 | 
				
			||||||
 | 
							        if (asMap) {
 | 
				
			||||||
 | 
							            for (const key of Object.keys(a)) {
 | 
				
			||||||
 | 
							                a[key] = new classs(a[key]);
 | 
				
			||||||
 | 
							            }
 | 
				
			||||||
 | 
							            return a;
 | 
				
			||||||
 | 
							        }
 | 
				
			||||||
 | 
							        return new classs(a);
 | 
				
			||||||
 | 
							    }
 | 
				
			||||||
 | 
							    return a;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										9
									
								
								go.mod
									
									
									
									
									
								
							
							
						
						
									
										9
									
								
								go.mod
									
									
									
									
									
								
							| 
						 | 
					@ -1,8 +1,13 @@
 | 
				
			||||||
module dequoter
 | 
					module dequoter
 | 
				
			||||||
 | 
					
 | 
				
			||||||
go 1.23
 | 
					go 1.23.3
 | 
				
			||||||
 | 
					
 | 
				
			||||||
require github.com/wailsapp/wails/v2 v2.10.2
 | 
					toolchain go1.24.3
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					require (
 | 
				
			||||||
 | 
						github.com/wailsapp/wails/v2 v2.10.2
 | 
				
			||||||
 | 
						lmika.dev/pkg/modash v0.0.0-20250729120720-cdaa1c8abbe3
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
require (
 | 
					require (
 | 
				
			||||||
	github.com/bep/debounce v1.2.1 // indirect
 | 
						github.com/bep/debounce v1.2.1 // indirect
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										2
									
								
								go.sum
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								go.sum
									
									
									
									
									
								
							| 
						 | 
					@ -79,3 +79,5 @@ golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY=
 | 
				
			||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
 | 
					golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
 | 
				
			||||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
 | 
					gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
 | 
				
			||||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
 | 
					gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
 | 
				
			||||||
 | 
					lmika.dev/pkg/modash v0.0.0-20250729120720-cdaa1c8abbe3 h1:EqYZdM6ui++F2NPdFCjKAboOr14eVTIIiRfngBgg/WA=
 | 
				
			||||||
 | 
					lmika.dev/pkg/modash v0.0.0-20250729120720-cdaa1c8abbe3/go.mod h1:8NDl/yR1eCCEhip9FJlVuMNXIeaztQ0Ks/tizExFcTI=
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										2
									
								
								main.go
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								main.go
									
									
									
									
									
								
							| 
						 | 
					@ -17,7 +17,7 @@ func main() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Create application with options
 | 
						// Create application with options
 | 
				
			||||||
	err := wails.Run(&options.App{
 | 
						err := wails.Run(&options.App{
 | 
				
			||||||
		Title:  "dequoter",
 | 
							Title:  "Dequoter",
 | 
				
			||||||
		Width:  1024,
 | 
							Width:  1024,
 | 
				
			||||||
		Height: 768,
 | 
							Height: 768,
 | 
				
			||||||
		AssetServer: &assetserver.Options{
 | 
							AssetServer: &assetserver.Options{
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										16
									
								
								models.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								models.go
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,16 @@
 | 
				
			||||||
 | 
					package main
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type TextSpan struct {
 | 
				
			||||||
 | 
						Text string `json:"text"`
 | 
				
			||||||
 | 
						Pos  int    `json:"pos"`
 | 
				
			||||||
 | 
						Len  int    `json:"len"`
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type ProcessTextRequest struct {
 | 
				
			||||||
 | 
						Action string     `json:"action"`
 | 
				
			||||||
 | 
						Input  []TextSpan `json:"input"`
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type ProcessTextResponse struct {
 | 
				
			||||||
 | 
						Output []TextSpan `json:"output"`
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										22
									
								
								textfilters.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								textfilters.go
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,22 @@
 | 
				
			||||||
 | 
					package main
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"bytes"
 | 
				
			||||||
 | 
						"encoding/json"
 | 
				
			||||||
 | 
						"strconv"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type TextFilter func(input string) (output string, err error)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var TextFilters = map[string]TextFilter{
 | 
				
			||||||
 | 
						"unquote": func(input string) (output string, err error) {
 | 
				
			||||||
 | 
							return strconv.Unquote(input)
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
						"format-json": func(input string) (output string, err error) {
 | 
				
			||||||
 | 
							var dst bytes.Buffer
 | 
				
			||||||
 | 
							if err := json.Indent(&dst, []byte(input), "", "  "); err != nil {
 | 
				
			||||||
 | 
								return "", err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return dst.String(), nil
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
		Loading…
	
		Reference in a new issue