support multiline

This commit is contained in:
Sam Hoffman
2026-01-18 19:20:31 -05:00
parent 78a1be39eb
commit b05827712b
4 changed files with 107 additions and 16 deletions

View File

@@ -17,12 +17,16 @@ const accountStore = useAccountStore();
<BufferList />
</v-sheet>
<div class="messages d-flex flex-column">
<v-toolbar density="compact">
<v-toolbar-title>
<p>{{ bufferStore.activeBufferName }}</p>
{{ bufferStore.activeBuffer?.topic }}
</v-toolbar-title>
</v-toolbar>
<v-card-title>
<v-row>
<v-col cols="2">
{{ bufferStore.activeBufferName }}
</v-col>
<v-col cols="3">
{{ bufferStore.activeBuffer?.topic }}
</v-col>
</v-row>
</v-card-title>
<MessageList
:messages="bufferStore.activeBuffer?.messages"
:me="accountStore.account.nick"

View File

@@ -103,6 +103,7 @@ function tabComplete() {
const beforeCursor = text.value.splice(0, cursor);
const afterCursor = text.value.slice(cursor);
}
const rows = ref(1);
</script>
<template>
<v-menu
@@ -114,16 +115,18 @@ function tabComplete() {
>
<v-list v-bind="menuList" @click:select="clickItem" />
</v-menu>
<v-text-field
<v-textarea
:rows="rows"
auto-grow
v-model="text"
autofocus
hide-details
:placeholder="`Message ${bufferStore.activeBufferName}`"
@input="trigger"
@keydown.enter.prevent="send"
@keydown.enter.exact.prevent="send"
@keydown.tab.prevent="tabComplete"
variant="outlined"
class="ma-1"
role="irchad"
></v-text-field>
/>
</template>

View File

@@ -61,7 +61,7 @@ watch(
><v-icon class="mr-2">mdi-eye</v-icon>Only visible to you
</v-chip>
</v-list-item-title>
{{ msg.message }}
<pre style="white-space: pre">{{ msg.message }}</pre>
</v-list-item></template
>
</v-virtual-scroll>

View File

@@ -12,12 +12,19 @@ export enum HookStatus {
HOOK_EAT,
}
interface Batch {
type: string;
target: string;
messages: any[];
params: string[];
}
export const useIRCStore = defineStore("ircStore", () => {
const bufferStore = useBufferStore();
const accountStore = useAccountStore();
const connected = ref(false);
const { authError } = storeToRefs(accountStore);
const batches = new Map<string, Batch>();
const hooks = {} as Record<string, HookFunction[]>;
function registerHook(event: string, f: HookFunction) {
@@ -103,6 +110,7 @@ export const useIRCStore = defineStore("ircStore", () => {
client.requestCap("draft/metadata-2");
client.requestCap("echo-message");
client.requestCap("chathistory");
client.requestCap("draft/multiline");
const tls = location.protocol === "https:";
const connectParams = {
host: location.hostname,
@@ -127,9 +135,27 @@ export const useIRCStore = defineStore("ircStore", () => {
if (!bufferStore.activeBuffer) {
return;
}
if (bufferStore.activeBuffer.channel)
bufferStore.activeBuffer.channel.say(message);
else client.say(bufferStore.activeBuffer.name, message);
send(bufferStore.activeBuffer?.name, message);
}
function genBatchId(): string {
return Math.random().toString(36).substring(2, 10);
}
function send(target: string, message: string) {
if (!message.includes("\n")) {
client.say(target, message);
return;
}
const split = message.split("\n");
const batchId = genBatchId();
client.raw(`BATCH +${batchId} draft/multiline ${target}`);
split.forEach((line) => {
client.raw(`@batch=${batchId} PRIVMSG ${target} :${line}`);
});
client.raw(`BATCH -${batchId}`);
}
function isMe(target: string) {
@@ -143,6 +169,7 @@ export const useIRCStore = defineStore("ircStore", () => {
}
client.on("socket close", () => {
batches.clear();
connected.value = false;
});
@@ -242,7 +269,7 @@ export const useIRCStore = defineStore("ircStore", () => {
},
);
client.on("message", function (message: { nick: string; target: string }) {
function handleMessage(message: any) {
let buffer;
const retVal = runHook("message", message);
@@ -270,7 +297,25 @@ export const useIRCStore = defineStore("ircStore", () => {
) {
buffer.resetLastSeen();
}
});
}
client.on(
"message",
function (message: {
nick: string;
target: string;
tags: Record<string, string>;
}) {
const batchId = message.tags["batch"];
if (batchId && batches.has(batchId)) {
batches.get(batchId)?.messages.push(message);
return;
}
handleMessage(message);
},
);
client.on("notice", function (message) {
const retVal = runHook("notice", message);
@@ -335,6 +380,45 @@ export const useIRCStore = defineStore("ircStore", () => {
buffer.users = ev.users;
});
client.on("batch start", (event: any) => {
batches.set(event.id, {
type: event.type,
target: event.params[0],
messages: [],
params: event.params,
});
});
function handleChatHistory(batch: Batch) {
for (const message of batch.messages) {
handleMessage(message);
}
}
function handleMultiline(batch: Batch) {
console.log(batch);
let m = "";
for (const message of batch.messages) {
m += `${message.message}\n`;
}
handleMessage({ ...batch.messages[0], message: m });
}
client.on("batch end draft/multiline", (event: any) => {
const batch = batches.get(event.id);
if (!batch) return;
handleMultiline(batch);
batches.delete(event.id);
});
client.on("batch end chathistory", (event: any) => {
const batch = batches.get(event.id);
if (!batch) return;
handleChatHistory(batch);
batches.delete(event.id);
});
return {
connect,
client,