#VariousComplements
## 経緯
- [Is it possible to add Arabic? · Issue #2 · tadashi-aikawa/obsidian-various-complements-plugin](https://github.com/tadashi-aikawa/obsidian-various-complements-plugin/issues/2)
- [Language independent? (Or adding German) · Issue #3 · tadashi-aikawa/obsidian-various-complements-plugin](https://github.com/tadashi-aikawa/obsidian-various-complements-plugin/issues/3)
## やること
- [x] ホワイトスペース区切りでトークナイズできるようにする
- [x] 日本語とそれ以外でコマンド名を切り替える
- [x] 動作確認
- [x] 英語
- [x] 日本語
- [x] ドイツ語
- [x] アラビア語
###
### ホワイトスペース区切りでトークナイズできるようにする
[[CodeMirror]]の`getLineTokens`を使うとそれっぽい結果がとれる。
```ts
function pickTokens(cmEditor: Editor): string[] {
const maxLineIndex = cmEditor.getDoc().lineCount();
return [...Array(maxLineIndex).keys()]
.flatMap((x) => cmEditor.getLineTokens(x).map((x) => x.string))
.map((x) => x.replace(/[\[\]()<>"'.,|; `]/g, ""))
.filter((x) => x !== "");
}
```
### 日本語とそれ以外でコマンド名を切り替える
`tokenizer.ts`を分離して抽象+Factory化。
| コマンド名 | デフォルトショートカット | 説明 |
| ------------------------- | ------------------------ | -------------------- |
| Auto Complete | `Ctrl + Space` | 空白区切り言語の補完 |
| Auto Complete as Japanese | | 日本語の補完 |
```ts
import TinySegmenter from "./tiny-segmenter";
import CodeMirror from "codemirror";
// @ts-ignore
const segmenter = new TinySegmenter();
export type TokenizeStrategy = "default" | "japanese";
function pickTokens(cmEditor: CodeMirror.Editor): string[] {
const maxLineIndex = cmEditor.getDoc().lineCount();
return [...Array(maxLineIndex).keys()]
.flatMap((x) => cmEditor.getLineTokens(x).map((x) => x.string))
.map((x) => x.replace(/[\[\]()<>"'.,|; `]/g, ""))
.filter((x) => x !== "");
}
function pickTokensAsJapanese(cmEditor: CodeMirror.Editor): string[] {
return cmEditor
.getValue()
.split(`\n`)
.flatMap<string>((x) => segmenter.segment(x))
.map((x) => x.replace(/[\[\]()<>"'.,|; `]/, ""));
}
interface TokenizedResult {
currentToken: string;
currentTokenStart: number;
tokens: string[];
}
interface Tokenizer {
/**
* Return undefined if current token is empty.
*/
tokenize(): TokenizedResult | undefined;
}
class DefaultTokenizer implements Tokenizer {
private readonly cmEditor: CodeMirror.Editor;
constructor(cmEditor: CodeMirror.Editor) {
this.cmEditor = cmEditor;
}
tokenize(): TokenizedResult | undefined {
const cursor = this.cmEditor.getCursor();
const token = this.cmEditor.getTokenAt(cursor);
if (!token.string) {
return undefined;
}
return {
currentToken: token.string,
currentTokenStart: token.start,
tokens: pickTokens(this.cmEditor),
};
}
}
class JapaneseTokenizer implements Tokenizer {
private readonly cmEditor: CodeMirror.Editor;
constructor(cmEditor: CodeMirror.Editor) {
this.cmEditor = cmEditor;
}
tokenize(): TokenizedResult | undefined {
const cursor = this.cmEditor.getCursor();
const token = this.cmEditor.getTokenAt(cursor);
if (!token.string) {
return undefined;
}
const words = segmenter.segment(token.string);
const currentToken = words.pop();
const currentTokenStart =
token.start + words.reduce((t: number, x: string) => t + x.length, 0);
const tokens = pickTokensAsJapanese(this.cmEditor);
return {
currentToken,
currentTokenStart,
tokens,
};
}
}
export function createTokenizer(
cmEditor: CodeMirror.Editor,
strategy: TokenizeStrategy
): Tokenizer {
switch (strategy) {
case "default":
return new DefaultTokenizer(cmEditor);
case "japanese":
return new JapaneseTokenizer(cmEditor);
default:
throw new Error(`Unexpected strategy name: ${strategy}`);
}
}
```
### 動作確認
`Japanese`
```
Obsidian用のこのプラグインを使用すると、マークダウンファイルへの入力を補完できます。
```
Obsidian用のこのプラグインを使用すると、マークダウンファイルへの入力を補完できます。
`English`
```
This plugin for Obsidian enables you to complement input in markdown files.
```
This plugin for Obsidian enables you to complement input in markdown files.
`German`
```
Mit diesem Plugin für Obsidian können Sie Eingaben in Markdown-Dateien ergänzen.
```
ergän
`Arabic`
```
يمكّنك هذا المكون الإضافي لـ Obsidian من استكمال الإدخال في ملفات markdown.
```
الإدخال
## 備考
### code blockの中はスペースが詰まって正しく補完されない問題
typeが`hmd-codeblock`を含む場合は更に空白でtokenize。