Skip to content

Commit

Permalink
Merge pull request #125 from AsPulse/feat/load-rule-file
Browse files Browse the repository at this point in the history
かなテーブル(.rules)を読み込めるようにする
  • Loading branch information
Shougo committed Jul 4, 2023
2 parents 8bd1781 + 5ea61ca commit 71e50cf
Show file tree
Hide file tree
Showing 8 changed files with 167 additions and 46 deletions.
42 changes: 35 additions & 7 deletions denops/skkeleton/config.ts
Original file line number Diff line number Diff line change
@@ -1,24 +1,27 @@
import { Denops } from "./deps.ts";
import {
assertBoolean,
assertNumber,
assertString,
isArray,
isString,
} from "./deps/unknownutil.ts";
import { getKanaTable } from "./kana.ts";
import { Encode, Encoding } from "./types.ts";
import { getKanaTable, loadKanaTableFiles } from "./kana.ts";
import { ConfigOptions, Encode, Encoding } from "./types.ts";
import { homeExpand } from "./util.ts";

export const config = {
export const config: ConfigOptions = {
acceptIllegalResult: false,
completionRankFile: "",
debug: false,
eggLikeNewline: false,
globalDictionaries: [] as (string | [string, string])[],
globalDictionaries: [],
globalJisyo: "/usr/share/skk/SKK-JISYO.L",
globalJisyoEncoding: "euc-jp",
immediatelyCancel: true,
immediatelyJisyoRW: true,
kanaTable: "rom",
globalKanaTableFiles: [],
keepState: false,
markerHenkan: "▽",
markerHenkanSelect: "▼",
Expand All @@ -28,8 +31,8 @@ export const config = {
showCandidatesCount: 4,
skkServerHost: "127.0.0.1",
skkServerPort: 1178,
skkServerReqEnc: "euc-jp" as Encoding,
skkServerResEnc: "euc-jp" as Encoding,
skkServerReqEnc: "euc-jp",
skkServerResEnc: "euc-jp",
usePopup: true,
useSkkServer: false,
userJisyo: "~/.skkeleton",
Expand Down Expand Up @@ -67,6 +70,19 @@ const validators: Validators = {
throw TypeError("can't use undefined kanaTable: " + x);
}
},
globalKanaTableFiles: (x): asserts x is (string | [string, string])[] => {
if (
!isArray(
x,
(x): x is string | [string, string] =>
isString(x) || isArray(x, isString) && x.length === 2,
)
) {
throw TypeError(
"'globalKanaTableFiles' must be array of two string tuple",
);
}
},
keepState: assertBoolean,
markerHenkan: assertString,
markerHenkanSelect: assertString,
Expand Down Expand Up @@ -98,7 +114,10 @@ const validators: Validators = {
userJisyo: assertString,
};

export function setConfig(newConfig: Record<string, unknown>) {
export async function setConfig(
newConfig: Record<string, unknown>,
denops: Denops,
) {
const cfg = config as Record<string, unknown>;
const val = validators as Record<string, (x: unknown) => void>;
if (config.debug) {
Expand All @@ -117,4 +136,13 @@ export function setConfig(newConfig: Record<string, unknown>) {
throw Error(`Illegal option detected: ${e}`);
}
}

const files = config.globalKanaTableFiles.map(async (
x,
): Promise<string | [string, string]> =>
Array.isArray(x)
? [await homeExpand(x[0], denops), x[1]]
: await homeExpand(x, denops)
);
await loadKanaTableFiles(await Promise.all(files));
}
19 changes: 5 additions & 14 deletions denops/skkeleton/jisyo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import type {
RankData,
SkkServerOptions,
} from "./types.ts";
import { readFileWithEncoding } from "./util.ts";

const okuriAriMarker = ";; okuri-ari entries.";
const okuriNasiMarker = ";; okuri-nasi entries.";
Expand Down Expand Up @@ -228,13 +229,12 @@ export class SKKDictionary implements Dictionary {
return candidates;
}

async load(path: string, encoding: string) {
load(data: string) {
let mode = -1;
this.#okuriAri = new Map();
this.#okuriNasi = new Map();
const a: Map<string, string[]>[] = [this.#okuriAri, this.#okuriNasi];
const decoder = new TextDecoder(encoding);
const lines = decoder.decode(await Deno.readFile(path)).split("\n");
const lines = data.split("\n");
for (const line of lines) {
if (line === okuriAriMarker) {
mode = 0;
Expand Down Expand Up @@ -633,26 +633,17 @@ export class Library {
}
}

const encodingNames: Record<string, string> = {
"EUCJP": "euc-jp",
"SJIS": "shift-jis",
"UTF8": "utf-8",
};

export async function load(
globalDictionaryConfig: (string | [string, string])[],
userDictionaryPath: UserDictionaryPath,
skkServer?: SkkServer,
): Promise<Library> {
const globalDictionaries = await Promise.all(
globalDictionaryConfig.map(async ([path, encodingName]) => {
if (encodingName === "") {
const data = await Deno.readFile(path);
encodingName = encodingNames[String(encoding.detect(data))];
}
const dict = new SKKDictionary();
try {
await dict.load(path, encodingName);
const file = await readFileWithEncoding(path, encodingName);
dict.load(file);
} catch (e) {
console.error("globalDictionary loading failed");
console.error(`at ${path}`);
Expand Down
3 changes: 2 additions & 1 deletion denops/skkeleton/jisyo_test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
UserDictionary,
wrapDictionary,
} from "./jisyo.ts";
import { readFileWithEncoding } from "./util.ts";

const globalJisyo = join(
dirname(fromFileUrl(import.meta.url)),
Expand Down Expand Up @@ -34,7 +35,7 @@ const numIncludingJisyo = join(

async function load(path: string, encoding: string): Promise<SKKDictionary> {
const dic = new SKKDictionary();
await dic.load(path, encoding);
dic.load(await readFileWithEncoding(path, encoding));
return dic;
}

Expand Down
38 changes: 35 additions & 3 deletions denops/skkeleton/kana.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { functions } from "./function.ts";
import { romToHira } from "./kana/rom_hira.ts";
import { romToZen } from "./kana/rom_zen.ts";
import type { KanaResult, KanaTable } from "./kana/type.ts";
import { Cell } from "./util.ts";
import { Cell, readFileWithEncoding } from "./util.ts";

const tables: Cell<Record<string, KanaTable>> = new Cell(() => ({
"rom": romToHira,
Expand Down Expand Up @@ -52,11 +52,43 @@ export function registerKanaTable(
const table: KanaTable = Object.entries(rawTable).map((
e,
) => [e[0], asKanaResult(e[1])]);
injectKanaTable(name, table, create);
}

export async function loadKanaTableFiles(
payload: (string | [string, string])[],
): Promise<void> {
const table: KanaTable = [];

const tasks = payload.map(async (v) => {
const [path, encodingName] = Array.isArray(v) ? v : [v, undefined];
const file = await readFileWithEncoding(path, encodingName);
const lines = file.split("\n");
for (const line of lines) {
if (line.startsWith("#")) {
continue;
}
if (line.trim() === "") {
continue;
}
const [from, result] = line.split(",");
table.push([from, [result, ""]]);
}
});

await Promise.all(tasks);
injectKanaTable("rom", table);
}

/*
* Concat given kanaTable to the table named `name`.
* When the table is not found, create if create=true; otherwise throws `table ${name} is not found`.
*/
function injectKanaTable(name: string, table: KanaTable, create = false) {
const t = tables.get();
if (!t[name] && !create) {
throw Error(`table ${name} is not found.`);
}
const newTable = distinctBy([...table, ...t[name] ?? []], (it) => it[0])
t[name] = distinctBy([...table, ...t[name] ?? []], (it) => it[0])
.sort((a, b) => a[0].localeCompare(b[0]));
t[name] = newTable;
}
33 changes: 13 additions & 20 deletions denops/skkeleton/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { handleKey, registerKeyMap } from "./keymap.ts";
import { keyToNotation, notationToKey, receiveNotation } from "./notation.ts";
import { currentContext, currentLibrary } from "./store.ts";
import type { CompletionData, RankData, SkkServerOptions } from "./types.ts";
import { homeExpand } from "./util.ts";

type Opts = {
key: string;
Expand Down Expand Up @@ -55,14 +56,6 @@ function assertOpts(x: unknown): asserts x is Opts {

let initialized = false;

function homeExpand(path: string, homePath: string): string {
if (path[0] === "~") {
return homePath + path.slice(1);
} else {
return path;
}
}

async function init(denops: Denops) {
if (initialized) {
return;
Expand Down Expand Up @@ -97,26 +90,26 @@ async function init(denops: Denops) {
};
skkServer = new SkkServer(skkServerOptions);
}
const homePath = await fn.expand(denops, "~") as string;
const globalDictionaries =
const globalDictionaries = await Promise.all(
(config.globalDictionaries.length === 0
? [[config.globalJisyo, config.globalJisyoEncoding]]
: config.globalDictionaries)
.map((
.map(async (
cfg,
): [string, string] => {
): Promise<[string, string]> => {
if (typeof (cfg) === "string") {
return [homeExpand(cfg, homePath), ""];
return [await homeExpand(cfg, denops), ""];
} else {
return [homeExpand(cfg[0], homePath), cfg[1]];
return [await homeExpand(cfg[0], denops), cfg[1]];
}
});
}),
);
currentLibrary.setInitializer(async () =>
await jisyoLoad(
globalDictionaries,
{
path: homeExpand(userJisyo, homePath),
rankPath: homeExpand(completionRankFile, homePath),
path: await homeExpand(userJisyo, denops),
rankPath: await homeExpand(completionRankFile, denops),
},
skkServer,
)
Expand Down Expand Up @@ -308,10 +301,10 @@ export async function main(denops: Denops) {
config.debug = true;
}
denops.dispatcher = {
config(config: unknown) {
async config(config: unknown) {
assertObject(config);
setConfig(config);
return Promise.resolve();
await setConfig(config, denops);
return;
},
async registerKeyMap(state: unknown, key: unknown, funcName: unknown) {
assertString(state);
Expand Down
28 changes: 28 additions & 0 deletions denops/skkeleton/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,31 @@ export type SkkServerOptions = {
requestEnc: Encoding;
responseEnc: Encoding;
} & Deno.ConnectOptions;

export type ConfigOptions = {
acceptIllegalResult: boolean;
completionRankFile: string;
debug: boolean;
eggLikeNewline: boolean;
globalDictionaries: (string | [string, string])[];
globalJisyo: string;
globalJisyoEncoding: Encoding;
immediatelyCancel: boolean;
immediatelyJisyoRW: boolean;
kanaTable: string;
globalKanaTableFiles: (string | [string, string])[];
keepState: boolean;
markerHenkan: string;
markerHenkanSelect: string;
registerConvertResult: boolean;
selectCandidateKeys: string;
setUndoPoint: boolean;
showCandidatesCount: number;
skkServerHost: string;
skkServerPort: number;
skkServerReqEnc: Encoding;
skkServerResEnc: Encoding;
usePopup: boolean;
useSkkServer: boolean;
userJisyo: string;
};
39 changes: 39 additions & 0 deletions denops/skkeleton/util.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
import { Denops, fn } from "./deps.ts";
import { encoding } from "./deps/encoding_japanese.ts";

export class Cell<T> {
initialized = false;
initializer: () => T;
Expand Down Expand Up @@ -62,3 +65,39 @@ export class LazyCell<T> {
this.lazyInitializer = initializer;
}
}

let homePath: string | undefined = undefined;
export async function homeExpand(
path: string,
denops: Denops,
): Promise<string> {
if (homePath === undefined) {
homePath = await fn.expand(denops, "~") as string;
}
if (path[0] === "~") {
return homePath + path.slice(1);
} else {
return path;
}
}

const encodingNames: Record<string, string> = {
"EUCJP": "euc-jp",
"SJIS": "shift-jis",
"UTF8": "utf-8",
};

export async function readFileWithEncoding(
path: string,
encodingName: string | undefined,
): Promise<string> {
const uint = await Deno.readFile(path);

// Use the argument if provided, otherwise try to detect the encoding.
const fileEncoding = encodingName !== undefined && encodingName !== ""
? encodingName
: encodingNames[String(encoding.detect(uint))];

const decoder = new TextDecoder(fileEncoding);
return decoder.decode(uint);
}
11 changes: 10 additions & 1 deletion doc/skkeleton.jax
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,7 @@ globalDictionaries *skkeleton-config-globalDictionaries*
値の例: [["/usr/share/skk/SKK-JISYO.L", "euc-jp"],
"~/.skk/SKK-JISYO.emoji"]
<

globalJisyo *skkeleton-config-globalJisyo*
(デフォルト "/usr/share/skk/SKK-JISYO.L")
グローバル辞書のパス
Expand Down Expand Up @@ -241,7 +242,15 @@ kanaTable *skkeleton-config-kanaTable*
存在するテーブルのみ指定できます。存在しないテーブルを指定したい場合は
|skkeleton#register_kanatable()| で先にテーブルを作成してください。


globalKanaTableFiles *skkeleton-config-globalKanaTableFiles*
(デフォルト [])
複数のカナ変換テーブルを使用する際に指定するオプションです。
指定する値はグローバル辞書のパスまたは
パスとエンコーディングからなるタプルの配列になります。
エンコーディングを指定しない場合は自動判定されます。
>
値の例: [["/usr/share/skk/azik_us.rule, "euc-jp"]]
<
keepState *skkeleton-config-keepState*
(デフォルト v:false)
このオプションを有効にすると
Expand Down

0 comments on commit 71e50cf

Please sign in to comment.