launcher: math mode

This commit is contained in:
2 * r + 2 * t 2025-03-04 23:26:05 +11:00
parent cf072f2f14
commit 35364193e3
4 changed files with 95 additions and 8 deletions

View file

@ -9,6 +9,10 @@
color: $colour;
}
.separator {
background-color: color.change($colour, $alpha: 0.7);
}
.search-bar {
.mode {
@include lib.border($colour, $width: 2);
@ -126,6 +130,16 @@
}
}
.math {
.preview > * {
margin-bottom: lib.s(10);
}
.result {
@include lib.spacing(10);
}
}
.swatches {
@include lib.spacing(3);
}

View file

@ -121,9 +121,10 @@ export default class Launcher extends PopupWindow {
this.hook(entry, "changed", () =>
(isAction(entry.get_text()) ? actions : content[mode.get()]).updateContent(entry.get_text())
);
this.hook(entry, "activate", () =>
(isAction(entry.get_text()) ? actions : content[mode.get()]).handleActivate(entry.get_text())
);
this.hook(entry, "activate", () => {
(isAction(entry.get_text()) ? actions : content[mode.get()]).handleActivate(entry.get_text());
entry.set_text(""); // Clear search on activate
});
// Clear search on hide if not in math mode or creating a todo
this.connect("hide", () => mode.get() !== "math" && !entry.text.startsWith(">todo") && entry.set_text(""));

View file

@ -1,8 +1,9 @@
import { Apps as AppsService } from "@/services/apps";
import MathService, { type HistoryItem } from "@/services/math";
import { getAppCategoryIcon } from "@/utils/icons";
import { launch } from "@/utils/system";
import { type FlowBox, setupCustomTooltip } from "@/utils/widgets";
import { execAsync, Gio, register } from "astal";
import { bind, execAsync, Gio, register, Variable } from "astal";
import { Astal, Gtk, Widget } from "astal/gtk3";
import { launcher as config } from "config";
import type AstalApps from "gi://AstalApps";
@ -71,6 +72,28 @@ const FileResult = ({ path }: { path: string }) => (
</Gtk.FlowBoxChild>
);
const MathResult = ({ icon, equation, result }: HistoryItem) => (
<Gtk.FlowBoxChild visible canFocus={false}>
<button
className="result"
cursor="pointer"
onClicked={() => {
execAsync(["wl-copy", "--", result]).catch(console.error);
close();
}}
setup={self => setupCustomTooltip(self, `${equation} -> ${result}`)}
>
<box>
<label className="icon" label={icon} />
<box vertical className="has-sublabel">
<label truncate xalign={0} label={equation} />
<label truncate xalign={0} label={result} className="sublabel" />
</box>
</box>
</button>
</Gtk.FlowBoxChild>
);
@register()
class Apps extends Widget.Box implements LauncherContent {
#content: FlowBox;
@ -133,16 +156,65 @@ class Files extends Widget.Box implements LauncherContent {
@register()
class Math extends Widget.Box implements LauncherContent {
#showResult: Variable<boolean>;
#result: Variable<HistoryItem>;
#content: FlowBox;
constructor() {
super({ name: "math", className: "math" });
super({ name: "math", className: "math", vertical: true });
this.#showResult = Variable(false);
this.#result = Variable({ equation: "", result: "", icon: "" });
this.#content = (<ContentBox />) as FlowBox;
this.add(
<revealer
transitionType={Gtk.RevealerTransitionType.SLIDE_DOWN}
transitionDuration={150}
revealChild={bind(this.#showResult)}
>
<box vertical className="preview">
<box className="result">
<label className="icon" label={bind(this.#result).as(r => r.icon)} />
<box vertical>
<label xalign={0} label="Result" />
<label
truncate
xalign={0}
className="sublabel"
label={bind(this.#result).as(r => r.result)}
/>
</box>
</box>
<box className="separator" />
</box>
</revealer>
);
this.add(
<scrollable expand hscroll={Gtk.PolicyType.NEVER}>
{this.#content}
</scrollable>
);
}
updateContent(search: string): void {
throw new Error("Method not implemented.");
this.#showResult.set(search.length > 0);
this.#result.set(MathService.get_default().evaluate(search));
this.#content.foreach(c => c.destroy());
for (const item of limitLength(MathService.get_default().history, config.math))
this.#content.add(<MathResult {...item} />);
}
handleActivate(search: string): void {
throw new Error("Method not implemented.");
if (!search) return;
MathService.get_default().commit();
const res = this.#result.get();
// Copy and close if not assignment, help or error
if (!["equal", "help", "error"].includes(res.icon)) {
execAsync(["wl-copy", "--", res.result]).catch(console.error);
close();
}
}
}

View file

@ -103,7 +103,7 @@ export default class Math extends GObject.Object {
} else if (equation.includes("=")) {
const [left, right] = equation.split("=");
try {
this.#variables[left.trim()] = simplify(right).toString();
this.#variables[left.trim()] = simplify(right, this.#variables).toString();
} catch {
this.#variables[left.trim()] = right.trim();
}