mirror of
https://github.com/ByteAtATime/raycast-linux.git
synced 2025-08-31 11:17:27 +00:00
feat(calculator): replace mathjs with SoulverCore
This commit replaces the `mathjs` library with the native SoulverCore engine for all calculations within the command palette. It updates the Swift wrapper to expose SoulverCore's functionality and modified the frontend to use the `calculate_soulver` command for evaluating expressions.
This commit is contained in:
parent
5f1ad1c84a
commit
5a5e609992
4 changed files with 102 additions and 89 deletions
|
@ -27,7 +27,6 @@
|
|||
"@tauri-apps/plugin-shell": "~2.2.1",
|
||||
"embla-carousel-svelte": "^8.6.0",
|
||||
"fuse.js": "^7.1.0",
|
||||
"mathjs": "^14.5.2",
|
||||
"msgpackr": "^1.11.4",
|
||||
"svelte-marked": "^0.8.0",
|
||||
"virtua": "^0.41.5",
|
||||
|
|
68
pnpm-lock.yaml
generated
68
pnpm-lock.yaml
generated
|
@ -44,9 +44,6 @@ importers:
|
|||
fuse.js:
|
||||
specifier: ^7.1.0
|
||||
version: 7.1.0
|
||||
mathjs:
|
||||
specifier: ^14.5.2
|
||||
version: 14.5.2
|
||||
msgpackr:
|
||||
specifier: ^1.11.4
|
||||
version: 1.11.4
|
||||
|
@ -224,10 +221,6 @@ packages:
|
|||
engines: {node: '>=6.0.0'}
|
||||
hasBin: true
|
||||
|
||||
'@babel/runtime@7.27.6':
|
||||
resolution: {integrity: sha512-vbavdySgbTTrmFE+EsiqUTzlOr5bzlnJtUv9PynGCAKvfQqjIXbvFdumPM/GxMDfyuGMJaJAU6TO4zc1Jf1i8Q==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
|
||||
'@babel/types@7.27.6':
|
||||
resolution: {integrity: sha512-ETyHEk2VHHvl9b9jZP5IHPavHYk57EhanlRRuae9XCpb/j5bDCbPPMOBfCWhnl/7EDJz0jEMCi/RhccCE8r1+Q==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
|
@ -1327,9 +1320,6 @@ packages:
|
|||
color-name@1.1.4:
|
||||
resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==}
|
||||
|
||||
complex.js@2.4.2:
|
||||
resolution: {integrity: sha512-qtx7HRhPGSCBtGiST4/WGHuW+zeaND/6Ld+db6PbrulIB1i2Ev/2UPiqcmpQNPSyfBKraC0EOvOKCB5dGZKt3g==}
|
||||
|
||||
concat-map@0.0.1:
|
||||
resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==}
|
||||
|
||||
|
@ -1383,9 +1373,6 @@ packages:
|
|||
supports-color:
|
||||
optional: true
|
||||
|
||||
decimal.js@10.5.0:
|
||||
resolution: {integrity: sha512-8vDa8Qxvr/+d94hSh5P3IJwI5t8/c0KsMp+g8bNw9cY2icONa5aPfvKeieW1WlG0WQYwwhJ7mjui2xtiePQSXw==}
|
||||
|
||||
decompress-response@6.0.0:
|
||||
resolution: {integrity: sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==}
|
||||
engines: {node: '>=10'}
|
||||
|
@ -1485,9 +1472,6 @@ packages:
|
|||
resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==}
|
||||
engines: {node: '>=6'}
|
||||
|
||||
escape-latex@1.2.0:
|
||||
resolution: {integrity: sha512-nV5aVWW1K0wEiUIEdZ4erkGGH8mDxGyxSeqPzRNtWP7ataw+/olFObw7hujFWlVjNsaDFw5VZ5NzVSIqRgfTiw==}
|
||||
|
||||
escape-string-regexp@4.0.0:
|
||||
resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==}
|
||||
engines: {node: '>=10'}
|
||||
|
@ -1631,10 +1615,6 @@ packages:
|
|||
resolution: {integrity: sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
fraction.js@5.2.2:
|
||||
resolution: {integrity: sha512-uXBDv5knpYmv/2gLzWQ5mBHGBRk9wcKTeWu6GLTUEQfjCxO09uM/mHDrojlL+Q1mVGIIFo149Gba7od1XPgSzQ==}
|
||||
engines: {node: '>= 12'}
|
||||
|
||||
from2@2.3.0:
|
||||
resolution: {integrity: sha512-OMcX/4IC/uqEPVgGeyfN22LJk6AZrMkRZHxcHBMBvHScDGgwTm2GT2Wkgtocyd3JfZffjj2kYUDXXII0Fk9W0g==}
|
||||
|
||||
|
@ -1852,9 +1832,6 @@ packages:
|
|||
engines: {node: '>=10'}
|
||||
hasBin: true
|
||||
|
||||
javascript-natural-sort@0.7.1:
|
||||
resolution: {integrity: sha512-nO6jcEfZWQXDhOiBtG2KvKyEptz7RVbpGP4vTD2hLBdmNQSsCiicO2Ioinv6UI4y9ukqnBpy+XZ9H6uLNgJTlw==}
|
||||
|
||||
jiti@2.4.2:
|
||||
resolution: {integrity: sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A==}
|
||||
hasBin: true
|
||||
|
@ -1994,11 +1971,6 @@ packages:
|
|||
resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
mathjs@14.5.2:
|
||||
resolution: {integrity: sha512-51U6hp7j4M4Rj+l+q2KbmXAV9EhQVQzUdw1wE67RnUkKKq5ibxdrl9Ky2YkSUEIc2+VU8/IsThZNu6QSHUoyTA==}
|
||||
engines: {node: '>= 18'}
|
||||
hasBin: true
|
||||
|
||||
md5.js@1.3.5:
|
||||
resolution: {integrity: sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==}
|
||||
|
||||
|
@ -2453,9 +2425,6 @@ packages:
|
|||
scheduler@0.26.0:
|
||||
resolution: {integrity: sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA==}
|
||||
|
||||
seedrandom@3.0.5:
|
||||
resolution: {integrity: sha512-8OwmbklUNzwezjGInmZ+2clQmExQPvomqjL7LFqOYqtmuxRgQYqOD3mHaU+MvZn5FLUeVxVfQjwLZW/n/JFuqg==}
|
||||
|
||||
semver@7.7.2:
|
||||
resolution: {integrity: sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==}
|
||||
engines: {node: '>=10'}
|
||||
|
@ -2638,9 +2607,6 @@ packages:
|
|||
resolution: {integrity: sha512-9phl76Cqm6FhSX9Xe1ZUAMLtm1BLkKj2Qd5ApyWkXzsMRaA7dgr81kf4wJmQf/hAvg8EEyJxDo3du/0KlhPiKQ==}
|
||||
engines: {node: '>=0.6.0'}
|
||||
|
||||
tiny-emitter@2.1.0:
|
||||
resolution: {integrity: sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q==}
|
||||
|
||||
tinyglobby@0.2.14:
|
||||
resolution: {integrity: sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ==}
|
||||
engines: {node: '>=12.0.0'}
|
||||
|
@ -2686,10 +2652,6 @@ packages:
|
|||
resolution: {integrity: sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==}
|
||||
engines: {node: '>=10'}
|
||||
|
||||
typed-function@4.2.1:
|
||||
resolution: {integrity: sha512-EGjWssW7Tsk4DGfE+5yluuljS1OGYWiI1J6e8puZz9nTMM51Oug8CD5Zo4gWMsOhq5BI+1bF+rWTm4Vbj3ivRA==}
|
||||
engines: {node: '>= 18'}
|
||||
|
||||
typescript-eslint@8.34.0:
|
||||
resolution: {integrity: sha512-MRpfN7uYjTrTGigFCt8sRyNqJFhjN0WwZecldaqhWm+wy0gaRt8Edb/3cuUy0zdq2opJWT6iXINKAtewnDOltQ==}
|
||||
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
||||
|
@ -2904,8 +2866,6 @@ snapshots:
|
|||
dependencies:
|
||||
'@babel/types': 7.27.6
|
||||
|
||||
'@babel/runtime@7.27.6': {}
|
||||
|
||||
'@babel/types@7.27.6':
|
||||
dependencies:
|
||||
'@babel/helper-string-parser': 7.27.1
|
||||
|
@ -3954,8 +3914,6 @@ snapshots:
|
|||
|
||||
color-name@1.1.4: {}
|
||||
|
||||
complex.js@2.4.2: {}
|
||||
|
||||
concat-map@0.0.1: {}
|
||||
|
||||
console-browserify@1.2.0: {}
|
||||
|
@ -4021,8 +3979,6 @@ snapshots:
|
|||
optionalDependencies:
|
||||
supports-color: 8.1.1
|
||||
|
||||
decimal.js@10.5.0: {}
|
||||
|
||||
decompress-response@6.0.0:
|
||||
dependencies:
|
||||
mimic-response: 3.1.0
|
||||
|
@ -4147,8 +4103,6 @@ snapshots:
|
|||
|
||||
escalade@3.2.0: {}
|
||||
|
||||
escape-latex@1.2.0: {}
|
||||
|
||||
escape-string-regexp@4.0.0: {}
|
||||
|
||||
eslint-config-prettier@10.1.5(eslint@9.28.0(jiti@2.4.2)):
|
||||
|
@ -4321,8 +4275,6 @@ snapshots:
|
|||
dependencies:
|
||||
is-callable: 1.2.7
|
||||
|
||||
fraction.js@5.2.2: {}
|
||||
|
||||
from2@2.3.0:
|
||||
dependencies:
|
||||
inherits: 2.0.4
|
||||
|
@ -4525,8 +4477,6 @@ snapshots:
|
|||
filelist: 1.0.4
|
||||
minimatch: 3.1.2
|
||||
|
||||
javascript-natural-sort@0.7.1: {}
|
||||
|
||||
jiti@2.4.2: {}
|
||||
|
||||
js-yaml@4.1.0:
|
||||
|
@ -4629,18 +4579,6 @@ snapshots:
|
|||
|
||||
math-intrinsics@1.1.0: {}
|
||||
|
||||
mathjs@14.5.2:
|
||||
dependencies:
|
||||
'@babel/runtime': 7.27.6
|
||||
complex.js: 2.4.2
|
||||
decimal.js: 10.5.0
|
||||
escape-latex: 1.2.0
|
||||
fraction.js: 5.2.2
|
||||
javascript-natural-sort: 0.7.1
|
||||
seedrandom: 3.0.5
|
||||
tiny-emitter: 2.1.0
|
||||
typed-function: 4.2.1
|
||||
|
||||
md5.js@1.3.5:
|
||||
dependencies:
|
||||
hash-base: 3.0.5
|
||||
|
@ -5079,8 +5017,6 @@ snapshots:
|
|||
|
||||
scheduler@0.26.0: {}
|
||||
|
||||
seedrandom@3.0.5: {}
|
||||
|
||||
semver@7.7.2: {}
|
||||
|
||||
set-cookie-parser@2.7.1: {}
|
||||
|
@ -5309,8 +5245,6 @@ snapshots:
|
|||
dependencies:
|
||||
setimmediate: 1.0.5
|
||||
|
||||
tiny-emitter@2.1.0: {}
|
||||
|
||||
tinyglobby@0.2.14:
|
||||
dependencies:
|
||||
fdir: 6.4.6(picomatch@4.0.2)
|
||||
|
@ -5348,8 +5282,6 @@ snapshots:
|
|||
|
||||
type-fest@0.21.3: {}
|
||||
|
||||
typed-function@4.2.1: {}
|
||||
|
||||
typescript-eslint@8.34.0(eslint@9.28.0(jiti@2.4.2))(typescript@5.6.3):
|
||||
dependencies:
|
||||
'@typescript-eslint/eslint-plugin': 8.34.0(@typescript-eslint/parser@8.34.0(eslint@9.28.0(jiti@2.4.2))(typescript@5.6.3))(eslint@9.28.0(jiti@2.4.2))(typescript@5.6.3)
|
||||
|
|
|
@ -1,6 +1,19 @@
|
|||
import SoulverCore
|
||||
import Foundation
|
||||
|
||||
struct SoulverResult: Codable {
|
||||
let value: String
|
||||
let type: String
|
||||
let error: String?
|
||||
|
||||
init(value: String, type: String, error: String? = nil) {
|
||||
self.value = value
|
||||
self.type = type
|
||||
self.error = error
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@MainActor
|
||||
private var globalCalculator: Calculator?
|
||||
|
||||
|
@ -32,17 +45,53 @@ public func initialize_soulver(resourcesPath: UnsafePointer<CChar>) {
|
|||
@MainActor
|
||||
@_cdecl("evaluate")
|
||||
public func evaluate(expression: UnsafePointer<CChar>) -> UnsafeMutablePointer<CChar>? {
|
||||
let encoder = JSONEncoder()
|
||||
|
||||
guard let calculator = globalCalculator else {
|
||||
let errorMsg = "Error: SoulverCore not initialized. Call initialize_soulver() first."
|
||||
print("❌ Soulver Wrapper: \(errorMsg)")
|
||||
return strdup(errorMsg)
|
||||
let errorResult = SoulverResult(value: "", type: "error", error: errorMsg)
|
||||
if let jsonData = try? encoder.encode(errorResult), let jsonString = String(data: jsonData, encoding: .utf8) {
|
||||
return strdup(jsonString)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
let swiftExpression = String(cString: expression)
|
||||
let result = calculator.calculate(swiftExpression)
|
||||
let resultString = result.stringValue
|
||||
|
||||
return strdup(resultString)
|
||||
if swiftExpression.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
|
||||
let emptyResult = SoulverResult(value: "", type: "none", error: nil)
|
||||
if let jsonData = try? encoder.encode(emptyResult), let jsonString = String(data: jsonData, encoding: .utf8) {
|
||||
return strdup(jsonString)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
let result = calculator.calculate(swiftExpression)
|
||||
|
||||
if result.isEmptyResult {
|
||||
let emptyResult = SoulverResult(value: "", type: "none", error: nil)
|
||||
if let jsonData = try? encoder.encode(emptyResult), let jsonString = String(data: jsonData, encoding: .utf8) {
|
||||
return strdup(jsonString)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
let resultType = String(describing: result.evaluationResult.equivalentTokenType)
|
||||
|
||||
let soulverResult = SoulverResult(value: result.stringValue, type: resultType)
|
||||
|
||||
if let jsonData = try? encoder.encode(soulverResult),
|
||||
let jsonString = String(data: jsonData, encoding: .utf8) {
|
||||
return strdup(jsonString)
|
||||
}
|
||||
|
||||
let errorMsg = "Failed to encode Soulver result to JSON."
|
||||
let errorResult = SoulverResult(value: "", type: "error", error: errorMsg)
|
||||
if let jsonData = try? encoder.encode(errorResult), let jsonString = String(data: jsonData, encoding: .utf8) {
|
||||
return strdup(jsonString)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@_cdecl("free_string")
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
import type { PluginInfo } from '@raycast-linux/protocol';
|
||||
import { invoke } from '@tauri-apps/api/core';
|
||||
import Fuse from 'fuse.js';
|
||||
import { create, all } from 'mathjs';
|
||||
import { writeText } from '@tauri-apps/plugin-clipboard-manager';
|
||||
import type { Quicklink } from '$lib/quicklinks.svelte';
|
||||
import { frecencyStore } from '$lib/frecency.svelte';
|
||||
import { frecencyStore } from './frecency.svelte';
|
||||
import { viewManager } from './viewManager.svelte';
|
||||
import type { App } from './apps.svelte';
|
||||
|
||||
|
@ -24,8 +23,6 @@ type UseCommandPaletteItemsArgs = {
|
|||
selectedQuicklinkForArgument: () => Quicklink | null;
|
||||
};
|
||||
|
||||
const math = create(all);
|
||||
|
||||
export function useCommandPaletteItems({
|
||||
searchText,
|
||||
plugins,
|
||||
|
@ -59,21 +56,58 @@ export function useCommandPaletteItems({
|
|||
})
|
||||
);
|
||||
|
||||
const calculatorResult = $derived.by(() => {
|
||||
let calculatorResult = $state<{ value: string; type: string } | null>(null);
|
||||
let calculationId = 0;
|
||||
|
||||
$effect(() => {
|
||||
const term = searchText();
|
||||
calculationId++;
|
||||
const currentCalculationId = calculationId;
|
||||
|
||||
if (!term.trim() || selectedQuicklinkForArgument()) {
|
||||
return null;
|
||||
calculatorResult = null;
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const result = math.evaluate(term.trim());
|
||||
if (typeof result === 'function' || typeof result === 'undefined') return null;
|
||||
const resultString = math.format(result, { precision: 14 });
|
||||
if (resultString === term.trim()) return null;
|
||||
return { value: resultString, type: math.typeOf(result) };
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
(async () => {
|
||||
try {
|
||||
const resultJson = await invoke<string>('calculate_soulver', { expression: term.trim() });
|
||||
|
||||
if (currentCalculationId !== calculationId) {
|
||||
return; // Stale request
|
||||
}
|
||||
|
||||
const result = JSON.parse(resultJson) as {
|
||||
value: string;
|
||||
type: string;
|
||||
error?: string;
|
||||
};
|
||||
|
||||
if (result.error) {
|
||||
console.error('Soulver error:', result.error);
|
||||
calculatorResult = null;
|
||||
return;
|
||||
}
|
||||
|
||||
if (result.type === 'none' || !result.value) {
|
||||
calculatorResult = null;
|
||||
return;
|
||||
}
|
||||
|
||||
if (result.value === term.trim()) {
|
||||
calculatorResult = null;
|
||||
return;
|
||||
}
|
||||
|
||||
calculatorResult = { value: result.value, type: result.type };
|
||||
} catch (e) {
|
||||
if (currentCalculationId !== calculationId) {
|
||||
return; // Stale request
|
||||
}
|
||||
console.error('Soulver invocation failed:', e);
|
||||
calculatorResult = null;
|
||||
}
|
||||
})();
|
||||
});
|
||||
|
||||
const displayItems = $derived.by(() => {
|
||||
|
@ -86,7 +120,6 @@ export function useCommandPaletteItems({
|
|||
score: 0,
|
||||
fuseScore: result.score
|
||||
}));
|
||||
console.log(items);
|
||||
} else {
|
||||
items = allSearchableItems.map((item) => ({ ...item, score: 0, fuseScore: 1 }));
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue