From 7c9023ae20c8169eed9a5a6fe7e0c1e6c83573ce Mon Sep 17 00:00:00 2001 From: Leon Mika Date: Wed, 6 May 2026 04:13:44 +0000 Subject: [PATCH 1/6] Reuse last prompt value when rerunning last command Co-authored-by: Shelley --- .../src/controllers/commands_controller.js | 8 ++++++++ frontend/src/controllers/prompt_controller.js | 20 ++++++++++++++++++- 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/frontend/src/controllers/commands_controller.js b/frontend/src/controllers/commands_controller.js index 5d74380..6bdc0b6 100644 --- a/frontend/src/controllers/commands_controller.js +++ b/frontend/src/controllers/commands_controller.js @@ -47,6 +47,7 @@ export class CommandsController extends Controller { runCommand(ev) { ev.preventDefault(); + this._promptController()?.clearUseLastValue(); textProcessor.runTextCommand(this.commandSelectTarget.value); this._lastCommand = this.commandSelectTarget.value; @@ -60,9 +61,16 @@ export class CommandsController extends Controller { return; } + this._promptController()?.useLastValueForNextPrompt(); textProcessor.runTextCommand(this._lastCommand); } + _promptController() { + const el = document.getElementById("prompt-dialog"); + if (!el) return null; + return this.application.getControllerForElementAndIdentifier(el, "prompt"); + } + _filterOptions(filterText) { let inputText = filterText.toLowerCase(); let inputTerms = filterText.toLowerCase().split(/\s+/).map(s => s.trim()).filter(s => s !== ""); diff --git a/frontend/src/controllers/prompt_controller.js b/frontend/src/controllers/prompt_controller.js index c8ff4e3..fe10ee0 100644 --- a/frontend/src/controllers/prompt_controller.js +++ b/frontend/src/controllers/prompt_controller.js @@ -8,8 +8,16 @@ export class PromptController extends Controller { connect() { this._callback = null; + this._lastValue = null; + this._useLastNext = false; window.runtime.EventsOn("prompt-request", (data) => { + if (this._useLastNext && this._lastValue !== null) { + this._useLastNext = false; + window.runtime.EventsEmit("prompt-response", this._lastValue); + return; + } + this._useLastNext = false; this.prompt(data.label, (res) => { window.runtime.EventsEmit("prompt-response", res); }); @@ -19,14 +27,16 @@ export class PromptController extends Controller { prompt(label, callback) { this._callback = callback; this.labelTarget.textContent = label; - this.inputTarget.value = ""; + this.inputTarget.value = this._lastValue || ""; this.element.showModal(); + this.inputTarget.select(); this.inputTarget.focus(); } submit(ev) { ev.preventDefault(); let value = this.inputTarget.value; + this._lastValue = value; this.element.close(); if (this._callback) { this._callback(value); @@ -39,4 +49,12 @@ export class PromptController extends Controller { this._callback = null; this.element.close(); } + + useLastValueForNextPrompt() { + this._useLastNext = true; + } + + clearUseLastValue() { + this._useLastNext = false; + } } From 5f221939e3af74ad43306da80572338be93d9b7a Mon Sep 17 00:00:00 2001 From: Leon Mika Date: Sat, 9 May 2026 12:22:25 +0000 Subject: [PATCH 2/6] Add Cmd+L to rerun last command on current line(s) Co-authored-by: Shelley --- frontend/index.html | 2 +- frontend/src/cmplugins.js | 8 +++++++ .../src/controllers/commands_controller.js | 13 +++++++++++- frontend/src/services.js | 21 ++++++++++++++++--- 4 files changed, 39 insertions(+), 5 deletions(-) diff --git a/frontend/index.html b/frontend/index.html index 43a2da8..708247a 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -20,7 +20,7 @@ + data-action="dq-showcommands@window->commands#showCommands dq-rerunlastcommand@window->commands#rerunLastCommand dq-rerunlastcommand-line@window->commands#rerunLastCommandOnLine">
{ + let event = new CustomEvent('dq-rerunlastcommand-line'); + window.dispatchEvent(event); + + return true; + } +}, { key: "Cmd-k", run: (view) => { const {state} = view; diff --git a/frontend/src/controllers/commands_controller.js b/frontend/src/controllers/commands_controller.js index 6bdc0b6..ec69f24 100644 --- a/frontend/src/controllers/commands_controller.js +++ b/frontend/src/controllers/commands_controller.js @@ -10,6 +10,10 @@ export class CommandsController extends Controller { "commandSelect", ]; + initialize() { + this._lineModeOnce = false; + } + async connect() { this._lastCommand = null; @@ -62,7 +66,14 @@ export class CommandsController extends Controller { } this._promptController()?.useLastValueForNextPrompt(); - textProcessor.runTextCommand(this._lastCommand); + const lineMode = this._lineModeOnce; + this._lineModeOnce = false; + textProcessor.runTextCommand(this._lastCommand, { lineMode }); + } + + rerunLastCommandOnLine(ev) { + this._lineModeOnce = true; + this.rerunLastCommand(ev); } _promptController() { diff --git a/frontend/src/services.js b/frontend/src/services.js index 88da2e0..2d65b6d 100644 --- a/frontend/src/services.js +++ b/frontend/src/services.js @@ -46,16 +46,31 @@ class TextProcessor { }); } - async runTextCommand(command) { + async runTextCommand(command, opts) { if (this._editor === undefined) { return; } + const lineMode = opts && opts.lineMode; let ranges = this._editor.state.selection.ranges; - let shouldBeAll = ranges.reduce((a, r) => a && r.from === r.to, true); + let hasSelection = ranges.some(r => r.from !== r.to); let inputs = []; - if (shouldBeAll) { + if (lineMode && !hasSelection) { + this._appendInsertPos = undefined; + const doc = this._editor.state.doc; + const seen = new Set(); + for (let r of ranges) { + const line = doc.lineAt(r.head); + if (seen.has(line.number)) continue; + seen.add(line.number); + inputs.push({ + text: line.text, + pos: line.from, + len: line.to - line.from, + }); + } + } else if (!hasSelection) { this._appendInsertPos = this._editor.state.selection.main.head; inputs.push({ text: this._editor.state.doc.toString(), From b25e3e378f4c22b5118e2d47d7ca92e201f9747d Mon Sep 17 00:00:00 2001 From: Leon Mika Date: Mon, 25 May 2026 20:05:05 +1000 Subject: [PATCH 3/6] Updated release build --- .forgejo/workflows/release.yml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/.forgejo/workflows/release.yml b/.forgejo/workflows/release.yml index edbbdd7..47c0989 100644 --- a/.forgejo/workflows/release.yml +++ b/.forgejo/workflows/release.yml @@ -21,9 +21,12 @@ jobs: - name: Running Wails doctor run: | wails doctor - - name: Build + - name: Installing Dependencies + working-directory: ./frontend run: | npm install + - name: Build + run: | wails build -clean -platform darwin/arm64 -ldflags "-X main.VersionNumber=`git describe --tags --abbrev=0`" - name: Release uses: https://lmika.dev/actions/wails-release@v1.0.3 @@ -35,7 +38,7 @@ jobs: notarization-api-issuer-id: ${{ secrets.MACOS_NOTARY_ISSUER_ID }} extra-build-flags: -ldflags "-X main.VersionNumber=${{ github.ref_name }}" s3-bucket: lmika-public-files - s3-key: Apps/Dequoter/{version}/{filename} + s3-key: 'Apps/Dequoter/{version}/{filename},Apps/Dequoter/latest/{filename}' s3-region: ap-southeast-2 s3-acl: public-read env: From 000f6790d441031b08d74125286c6c3f12bb0be8 Mon Sep 17 00:00:00 2001 From: Leon Mika Date: Mon, 25 May 2026 20:05:25 +1000 Subject: [PATCH 4/6] Bumped the release build version --- .forgejo/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.forgejo/workflows/release.yml b/.forgejo/workflows/release.yml index 47c0989..eded102 100644 --- a/.forgejo/workflows/release.yml +++ b/.forgejo/workflows/release.yml @@ -29,7 +29,7 @@ jobs: run: | wails build -clean -platform darwin/arm64 -ldflags "-X main.VersionNumber=`git describe --tags --abbrev=0`" - name: Release - uses: https://lmika.dev/actions/wails-release@v1.0.3 + uses: https://lmika.dev/actions/wails-release@v1.0.4 with: developer-id-cert-base64: ${{ secrets.MACOS_SIGN_P12 }} developer-id-cert-password: ${{ secrets.MACOS_SIGN_PASSWORD }} From d1f51f5d7b21f85e1451c3df5c802d8161e3ac44 Mon Sep 17 00:00:00 2001 From: Leon Mika Date: Mon, 25 May 2026 20:20:36 +1000 Subject: [PATCH 5/6] Fixed npm dir --- .forgejo/workflows/release.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.forgejo/workflows/release.yml b/.forgejo/workflows/release.yml index eded102..392e612 100644 --- a/.forgejo/workflows/release.yml +++ b/.forgejo/workflows/release.yml @@ -22,7 +22,6 @@ jobs: run: | wails doctor - name: Installing Dependencies - working-directory: ./frontend run: | npm install - name: Build From 44e4d09c3afe7033545f2c02bf9986edf3672737 Mon Sep 17 00:00:00 2001 From: Leon Mika Date: Wed, 24 Jun 2026 20:42:34 +1000 Subject: [PATCH 6/6] Added commands for base64 and JWT decoding --- textfilters.go | 69 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) diff --git a/textfilters.go b/textfilters.go index 1bd4334..e3ef6d7 100644 --- a/textfilters.go +++ b/textfilters.go @@ -4,6 +4,7 @@ import ( "bufio" "bytes" "context" + "encoding/base64" "encoding/json" "errors" "fmt" @@ -123,6 +124,32 @@ var TextFilters = map[string]TextProcessor{ return TextFilterResponse{Output: result}, nil }, }, + "compact-json": { + Label: "JSON: Compact", + Filter: func(ctx context.Context, input string) (resp TextFilterResponse, err error) { + var ( + dst bytes.Buffer + inBfr bytes.Buffer + outBfr bytes.Buffer + ) + + scnr := bufio.NewScanner(strings.NewReader(input)) + for scnr.Scan() { + line := scnr.Text() + inBfr.WriteString(line) + inBfr.WriteString("\n") + + if err := json.Compact(&outBfr, inBfr.Bytes()); err == nil { + dst.WriteString(outBfr.String()) + dst.WriteString("\n") + inBfr.Reset() + outBfr.Reset() + } + } + + return TextFilterResponse{Output: dst.String() + inBfr.String()}, nil + }, + }, "format-json": { Label: "JSON: Format", Filter: func(ctx context.Context, input string) (resp TextFilterResponse, err error) { @@ -173,6 +200,48 @@ var TextFilters = map[string]TextProcessor{ return TextFilterResponse{Output: string(jsonBytes)}, nil }, }, + "jwt-decode": { + Label: "JWT: Decode", + Filter: func(ctx context.Context, input string) (resp TextFilterResponse, err error) { + tokens := strings.Split(input, ".") + if len(tokens) != 3 { + return TextFilterResponse{}, errors.New("invalid JWT format") + } + + header, err := base64.RawURLEncoding.DecodeString(tokens[0]) + if err != nil { + return TextFilterResponse{}, err + } + payload, err := base64.RawURLEncoding.DecodeString(tokens[1]) + if err != nil { + return TextFilterResponse{}, err + } + + var headerJSON, payloadJSON bytes.Buffer + json.Indent(&headerJSON, header, "", " ") + json.Indent(&payloadJSON, payload, "", " ") + + return TextFilterResponse{Output: headerJSON.String() + "\n" + payloadJSON.String()}, nil + }, + }, + "base64-decode": { + Label: "Base64: Decode", + Filter: func(ctx context.Context, input string) (resp TextFilterResponse, err error) { + dst, err := base64.StdEncoding.DecodeString(input) + if err != nil { + return TextFilterResponse{}, err + } + + return TextFilterResponse{Output: string(dst)}, nil + }, + }, + "base64-encode": { + Label: "Base64: Encode", + Filter: func(ctx context.Context, input string) (resp TextFilterResponse, err error) { + dst := base64.StdEncoding.EncodeToString([]byte(input)) + return TextFilterResponse{Output: dst}, nil + }, + }, "lorem-ipsum": { Label: "Generate: Lorem Ipsum", Filter: func(ctx context.Context, input string) (resp TextFilterResponse, err error) {