mirror of
https://github.com/simplex-chat/simplex-chat.git
synced 2026-09-28 22:08:42 +00:00
replies
This commit is contained in:
@@ -8,7 +8,7 @@ Each user who connects via the bot's business address receives a calculator mess
|
||||
- `%` is computed as in Apple's calculator: `100 + 15 % =` equals 115.
|
||||
- Tap `C` to clear the number, and `C` again to clear the calculation.
|
||||
- Numbers are shown without exponent, up to 15 digits; larger results are shown as `Error`.
|
||||
- You can also send numbers, expressions like `(2 + 3) × 4`, which are entered as one number, and keys like `+`, `=`, `add` or `c`.
|
||||
- You can also send numbers and keys like `+`, `=`, `add` or `c`. Expressions like `(2 + 3) × 4` are entered as one number, and the bot replies to them with the result.
|
||||
- The bot deletes tapped keys and sends each calculation after `=`.
|
||||
- After 10 minutes without input, the bot turns the calculator off and discards the calculation; tap any key to turn it on.
|
||||
- The bot sends keys like `/+` to apps with chat protocol version 21 or later, and keys like `/add` to older apps.
|
||||
|
||||
@@ -6,7 +6,7 @@ type Input = {tap: string} | {text: string}
|
||||
function run(inputs: Input[]): {calc: Calc, logLines: string[]} {
|
||||
const logLines: string[] = []
|
||||
const calc = inputs.reduce((current, input) => {
|
||||
const [next, logLine] = "tap" in input ? press(current, input.tap as Key) : textInput(input.text)!(current)
|
||||
const [next, logLine] = "tap" in input ? press(current, input.tap as Key) : textInput(input.text)!.update(current)
|
||||
if (logLine) logLines.push(logLine)
|
||||
return next
|
||||
}, initialCalc)
|
||||
@@ -142,6 +142,18 @@ describe("typed messages", () => {
|
||||
expect(type("10", "+", "25=").calc.display).toBe("35")
|
||||
})
|
||||
|
||||
test("result only for expressions", () => {
|
||||
const result = (text: string) => textInput(text)?.result
|
||||
expect(result("(2 + 3) × 4")).toBe("20")
|
||||
expect(result("(2 + 3) × 4 =")).toBe("20")
|
||||
expect(result("15%")).toBe("0.15")
|
||||
expect(result("1 / 0")).toBe("Error")
|
||||
expect(result("25")).toBeUndefined()
|
||||
expect(result("-5")).toBeUndefined()
|
||||
expect(result("25=")).toBeUndefined()
|
||||
expect(result("+")).toBeUndefined()
|
||||
})
|
||||
|
||||
test("overflow in typed numbers", () => {
|
||||
expect(type("1234567890123456").calc.display).toBe("Error")
|
||||
expect(type("123456789012345").calc.display).toBe("123456789012345")
|
||||
|
||||
@@ -31,6 +31,9 @@ const calculatorShows = (display: string): ItemCheck => ci => ci.chatItem.meta.i
|
||||
|
||||
const hasText = (text: string): ItemCheck => ci => ci.chatItem.meta.itemText === text
|
||||
|
||||
const repliesTo = (quoted: string, text: string): ItemCheck => ({chatItem}) =>
|
||||
chatItem.meta.itemText === text && chatItem.quotedItem?.content.text === quoted
|
||||
|
||||
test("calculator in business chat", async () => {
|
||||
const dir = mkdtempSync(join(tmpdir(), "calculator-bot-"))
|
||||
const botDbOpts: bot.BotDbOpts = {type: "sqlite", filePrefix: join(dir, "bot")}
|
||||
@@ -54,7 +57,7 @@ test("calculator in business chat", async () => {
|
||||
for (const event of received) expect(await event).toBeDefined()
|
||||
}
|
||||
await send(["/2", "/+", "/2", "/="], hasText("2 + 2 = 4"), calculatorShows("4"))
|
||||
await send(["2 × (3 + 4) - 1"], calculatorShows("13"))
|
||||
await send(["2 × (3 + 4) - 1"], repliesTo("2 × (3 + 4) - 1", "= 13"), calculatorShows("13"))
|
||||
await send(["25", "+", "25", "="], hasText("25 + 25 = 50"), calculatorShows("50"))
|
||||
} finally {
|
||||
await alice.close()
|
||||
|
||||
@@ -157,17 +157,19 @@ function format(n: number): string {
|
||||
return trimmed === "-0" ? "0" : trimmed
|
||||
}
|
||||
|
||||
export function textInput(text: string): Update | undefined {
|
||||
export function textInput(text: string): {update: Update, result?: string} | undefined {
|
||||
const input = text.replace(/\s/g, "")
|
||||
const n = expressionValue(input.replace(/=$/, ""))
|
||||
const entry = input.replace(/=$/, "")
|
||||
const n = expressionValue(entry)
|
||||
if (n !== undefined) {
|
||||
return calc => {
|
||||
const update: Update = calc => {
|
||||
const entered = showNumber(calc, n)
|
||||
return input.endsWith("=") ? press(entered, "=") : [entered]
|
||||
}
|
||||
return {update, result: Number.isNaN(Number(entry)) ? format(n) : undefined}
|
||||
}
|
||||
const key = keyNames.get(input.toLowerCase())
|
||||
return key ? calc => press(calc, key) : undefined
|
||||
return key ? {update: calc => press(calc, key)} : undefined
|
||||
}
|
||||
|
||||
const tokenPattern = /\d+(?:\.\d*)?|\.\d+|[-+−×x*÷\/%()]/g
|
||||
|
||||
@@ -68,9 +68,13 @@ const keyCommands = Object.fromEntries([...keyNames].map(([name, key]) => [name,
|
||||
async function onMessage(ci: T.AChatItem, content: T.MsgContent, chat: api.ChatApi): Promise<void> {
|
||||
const sender = groupSender(ci)
|
||||
if (!sender || content.type !== "text") return
|
||||
const update = textInput(content.text)
|
||||
if (update) await updateCalculator(chat, sender, update)
|
||||
else await chat.apiSendTextReply(ci, hint)
|
||||
const input = textInput(content.text)
|
||||
if (!input) {
|
||||
await chat.apiSendTextReply(ci, hint)
|
||||
return
|
||||
}
|
||||
if (input.result) await chat.apiSendTextReply(ci, `= ${input.result}`)
|
||||
await updateCalculator(chat, sender, input.update)
|
||||
}
|
||||
|
||||
export function runCalculatorBot(dbOpts: bot.BotDbOpts): Promise<[api.ChatApi, T.User, T.UserContactLink | undefined]> {
|
||||
|
||||
Reference in New Issue
Block a user