Skip to content

Commit

Permalink
Pari Plus! note auto spacing
Browse files Browse the repository at this point in the history
  • Loading branch information
Natsuki-Kaede committed Oct 23, 2024
1 parent 0205565 commit 278a4a0
Show file tree
Hide file tree
Showing 9 changed files with 165 additions and 3 deletions.
3 changes: 3 additions & 0 deletions locales/en-US.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1289,6 +1289,9 @@ showDetailTimeWhenHover: "Hover the timestamp of the note to expand the detailed
noteClickToOpen: "Click to open note details"
enableFallbackReactButton: "Enable fallback reaction button"
enableMFMCheatsheet: "Enable MFM Cheatsheet in post form"
autoSpacing: "Auto Spacing"
autoSpacingDescription: "Adding spaces between CJK and English characters"
auto: "Auto"
performance: "Performance"
modified: "Modified"
discard: "Discard"
Expand Down
3 changes: 3 additions & 0 deletions locales/zh-CN.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1298,6 +1298,9 @@ showDetailTimeWhenHover: "悬浮/长按帖文时间戳时,展开详细时间"
noteClickToOpen: "点击展开帖文详情"
enableFallbackReactButton: "开启Fallback回应按钮"
enableMFMCheatsheet: "在帖文编辑框中启用MFM Cheatsheet"
autoSpacing: "自动空格"
autoSpacingDescription: "在CJK字符和英文字符中添加空格"
auto: "自动"
messageToFollower: "给关注者的消息"
target: "对象"
testCaptchaWarning: "这是用于验证码测试的功能。**请勿在生产环境中使用。**"
Expand Down
3 changes: 3 additions & 0 deletions locales/zh-TW.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1298,6 +1298,9 @@ showDetailTimeWhenHover: "長按貼文時間戳記時展開詳細時間"
noteClickToOpen: "點擊展開貼文詳情"
enableFallbackReactButton: "啓用Fallback回應鍵"
enableMFMCheatsheet: "在貼文編輯框中啓用MFM Cheatsheet"
autoSpacing: "自動間距"
autoSpacingDescription: "在CJK字符和英文字符中添加間距"
auto: "自動"
messageToFollower: "給追隨者的訊息"
target: "目標 "
testCaptchaWarning: "這是用於驗證碼測試的功能。**請勿在生產環境中使用。**"
Expand Down
3 changes: 2 additions & 1 deletion packages/frontend/src/components/MkNote.vue
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,7 @@ import { getAppearNote } from '@/scripts/get-appear-note.js';
import { useRouter } from '@/router/supplier.js';
import { miLocalStorage } from '@/local-storage.js';
import detectLanguage from '@/scripts/detect-language.js';
import { spacingNote } from '@/scripts/autospacing.js';
const props = withDefaults(defineProps<{
note: Misskey.entities.Note;
Expand Down Expand Up @@ -278,7 +279,7 @@ const renoteTime = shallowRef<HTMLElement>();
const reactButton = shallowRef<HTMLElement>();
const clipButton = shallowRef<HTMLElement>();
const likeButton = shallowRef<HTMLElement>();
const appearNote = computed(() => getAppearNote(note.value));
const appearNote = computed(() => spacingNote(getAppearNote(note.value)));
const galleryEl = shallowRef<InstanceType<typeof MkMediaList>>();
const isMyRenote = $i && ($i.id === note.value.userId);
const showContent = ref(false);
Expand Down
3 changes: 2 additions & 1 deletion packages/frontend/src/components/MkNoteDetailed.vue
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,7 @@ import { getAppearNote } from '@/scripts/get-appear-note.js';
import { type Keymap } from '@/scripts/hotkey.js';
import { miLocalStorage } from '@/local-storage.js';
import detectLanguage from '@/scripts/detect-language.js';
import { spacingNote } from '@/scripts/autospacing.js';
const props = withDefaults(defineProps<{
note: Misskey.entities.Note;
Expand Down Expand Up @@ -322,7 +323,7 @@ const reactButton = shallowRef<HTMLElement>();
const clipButton = shallowRef<HTMLElement>();
const likeButton = shallowRef<HTMLElement>();
const historyMenuButton = shallowRef<HTMLElement>();
const appearNote = computed(() => getAppearNote(note.value));
const appearNote = computed(() => spacingNote(getAppearNote(note.value)));
const galleryEl = shallowRef<InstanceType<typeof MkMediaList>>();
const isMyRenote = $i && ($i.id === note.value.userId);
const showContent = ref(false);
Expand Down
9 changes: 9 additions & 0 deletions packages/frontend/src/pages/settings/pari.vue
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,13 @@ SPDX-License-Identifier: AGPL-3.0-only
<MkSwitch v-model="noteClickToOpen">{{ i18n.ts.noteClickToOpen }}</MkSwitch>
<MkSwitch v-model="enableFallbackReactButton">{{ i18n.ts.enableFallbackReactButton }}</MkSwitch>
<MkSwitch v-model="enableMFMCheatsheet">{{ i18n.ts.enableMFMCheatsheet }}</MkSwitch>
<MkSelect v-model="autoSpacingBehaviour">
<template #label>{{ i18n.ts.autoSpacing }}</template>
<option :value="null">{{ i18n.ts.disabled }}</option>
<option value="all">{{ i18n.ts.all }}</option>
<option value="special">{{ i18n.ts.auto }}</option>
<template #caption>{{ i18n.ts.autoSpacingDescription }}</template>
</MkSelect>
</div>
</template>

Expand All @@ -20,12 +27,14 @@ import { i18n } from '@/i18n.js';
import { definePageMetadata } from '@/scripts/page-metadata.js';
import { defaultStore } from '@/store.js';
import MkSwitch from '@/components/MkSwitch.vue';
import MkSelect from '@/components/MkSelect.vue';
const autoTranslateButton = computed(defaultStore.makeGetterSetter('autoTranslateButton'));
const showDetailTimeWhenHover = computed(defaultStore.makeGetterSetter('showDetailTimeWhenHover'));
const noteClickToOpen = computed(defaultStore.makeGetterSetter('noteClickToOpen'));
const enableFallbackReactButton = computed(defaultStore.makeGetterSetter('enableFallbackReactButton'));
const enableMFMCheatsheet = computed(defaultStore.makeGetterSetter('enableMFMCheatsheet'));
const autoSpacingBehaviour = computed(defaultStore.makeGetterSetter('autoSpacingBehaviour'));
definePageMetadata(() => ({
title: 'Pari Plus!',
Expand Down
138 changes: 138 additions & 0 deletions packages/frontend/src/scripts/autospacing.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
import * as misskey from 'misskey-js';
import { defaultStore } from '@/store.js';

const NO_SPACEING_LIST = [
'A股',
'B股',
'H股',
'O型',
'A型',
'B型',
'AB型',
'RH阴性',
'RH阳性',
'IP地址',
'IP卡',
'SIM卡',
'IC卡',
'ID号',
'CD机',
'IT界',
'PC端',
'PM',
'PM2.5',
'PPT',
'QQ号',
'SQL注入',
'USB口',
'UV层',
'WiFi',
'T恤',
'A字裙',
'B字裙',
'H型',
'T型',
'X型',
'S码',
'M码',
'L码',
'XL码',
'XXL码',
'A站',
'B站',
'C站',
'N卡',
'A卡',
'UP主',
'X光',
'B超',
'CT室',
'PH值',
'X档案',
'Q弹',
'N倍',
'AA制',
'K歌',
'维生素A',
'维生素B',
'维生素C',
'维生素D',
'维生素E',
'阿Q',
'Q版',
'OA系统',
'PR值',
'A型柱',
'B型柱',
'N档',
'P档',
'R档',
'D档',
'3D打印',
];

const LIST_WINDOW = NO_SPACEING_LIST.reduce((a, b) => Math.max(a, b.length), 0) + 1;

const hashtagMap = new Map<string, string>();
let placeholderCounter = 0;

function preserveHashtags(text: string): string {
placeholderCounter = 0;
hashtagMap.clear();

return text.replace(/#[^\s]+/g, (match) => {
const placeholder = `__HASHTAG_${placeholderCounter}__`;
hashtagMap.set(placeholder, match);
placeholderCounter++;
return placeholder;
});
}

function restoreHashtags(text: string): string {
let result = text;
for (const [placeholder, hashtag] of hashtagMap) {
result = result.replace(placeholder, hashtag);
}
return result;
}

export function autoSpacing(plainText: string) {
if (defaultStore.reactiveState.autoSpacingBehaviour.value == null) return plainText;

const textWithPlaceholders = preserveHashtags(plainText);

const rep = (matched: string, c1: string, c2: string, position: number) => {
if (defaultStore.reactiveState.autoSpacingBehaviour.value === 'all') return `${c1} ${c2}`;
const context = plainText
.slice(Math.max(0, position - LIST_WINDOW), position + LIST_WINDOW)
.toUpperCase();
if (NO_SPACEING_LIST.some((text) => context.includes(text))) {
return matched;
} else {
return `${c1} ${c2}`;
}
};

const spacedText = textWithPlaceholders
.replace(/([\u4e00-\u9fa5\u0800-\u4e00\uac00-\ud7ff])([a-zA-Z0-9])/g, rep)
.replace(/([a-zA-Z0-9,\.:])([\u4e00-\u9fa5\u0800-\u4e00\uac00-\ud7ff])/g, rep);

return restoreHashtags(spacedText);
}

export function spacingNote(note: misskey.entities.Note) {
const noteAsRecord = note as unknown as Record<string, string | null | undefined>;
if (!noteAsRecord.__autospacing_raw_text) {
noteAsRecord.__autospacing_raw_text = note.text;
}
if (!noteAsRecord.__autospacing_raw_cw) {
noteAsRecord.__autospacing_raw_cw = note.cw;
}
note.text = noteAsRecord.__autospacing_raw_text
? autoSpacing(noteAsRecord.__autospacing_raw_text)
: null;
note.cw = noteAsRecord.__autospacing_raw_cw
? autoSpacing(noteAsRecord.__autospacing_raw_cw)
: null;
return note;
}
2 changes: 1 addition & 1 deletion packages/frontend/src/scripts/get-appear-note.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,5 @@
import * as Misskey from 'misskey-js';

export function getAppearNote(note: Misskey.entities.Note) {
return Misskey.note.isPureRenote(note) ? note.renote : note;
return Misskey.note.isPureRenote(note) ? note.renote! : note;
}
4 changes: 4 additions & 0 deletions packages/frontend/src/store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -527,6 +527,10 @@ export const defaultStore = markRaw(new Storage('base', {
where: 'device',
default: true,
},
autoSpacingBehaviour: {
where: 'device',
default: null as 'all' | 'special' | null,
},
}));

// TODO: 他のタブと永続化されたstateを同期
Expand Down

0 comments on commit 278a4a0

Please sign in to comment.