Make Keymap class
This commit is contained in:
parent
b496cea582
commit
410ffbb037
15 changed files with 223 additions and 129 deletions
|
@ -8,6 +8,7 @@ import AddonEnabledController from '../controllers/AddonEnabledController';
|
||||||
import LinkController from '../controllers/LinkController';
|
import LinkController from '../controllers/LinkController';
|
||||||
import OperationController from '../controllers/OperationController';
|
import OperationController from '../controllers/OperationController';
|
||||||
import MarkController from '../controllers/MarkController';
|
import MarkController from '../controllers/MarkController';
|
||||||
|
import { toJSON } from '../../shared/Settings';
|
||||||
|
|
||||||
@injectable()
|
@injectable()
|
||||||
export default class ContentMessageListener {
|
export default class ContentMessageListener {
|
||||||
|
@ -101,8 +102,8 @@ export default class ContentMessageListener {
|
||||||
return this.commandController.exec(text);
|
return this.commandController.exec(text);
|
||||||
}
|
}
|
||||||
|
|
||||||
onSettingsQuery(): Promise<any> {
|
async onSettingsQuery(): Promise<any> {
|
||||||
return this.settingController.getSetting();
|
return toJSON(await this.settingController.getSetting());
|
||||||
}
|
}
|
||||||
|
|
||||||
onFindGetKeyword(): Promise<string> {
|
onFindGetKeyword(): Promise<string> {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { injectable } from 'tsyringe';
|
import { injectable } from 'tsyringe';
|
||||||
import MemoryStorage from '../infrastructures/MemoryStorage';
|
import MemoryStorage from '../infrastructures/MemoryStorage';
|
||||||
import Settings from '../../shared/Settings';
|
import Settings, { valueOf, toJSON } from '../../shared/Settings';
|
||||||
import * as PropertyDefs from '../../shared/property-defs';
|
import * as PropertyDefs from '../../shared/property-defs';
|
||||||
|
|
||||||
const CACHED_SETTING_KEY = 'setting';
|
const CACHED_SETTING_KEY = 'setting';
|
||||||
|
@ -14,11 +14,13 @@ export default class SettingRepository {
|
||||||
}
|
}
|
||||||
|
|
||||||
get(): Promise<Settings> {
|
get(): Promise<Settings> {
|
||||||
return Promise.resolve(this.cache.get(CACHED_SETTING_KEY));
|
let data = this.cache.get(CACHED_SETTING_KEY);
|
||||||
|
return Promise.resolve(valueOf(data));
|
||||||
}
|
}
|
||||||
|
|
||||||
update(value: Settings): void {
|
update(value: Settings): void {
|
||||||
return this.cache.set(CACHED_SETTING_KEY, value);
|
let data = toJSON(value);
|
||||||
|
return this.cache.set(CACHED_SETTING_KEY, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
async setProperty(
|
async setProperty(
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import Settings from '../../shared/Settings';
|
import Settings, { valueOf } from '../../shared/Settings';
|
||||||
import * as messages from '../../shared/messages';
|
import * as messages from '../../shared/messages';
|
||||||
|
|
||||||
export default interface SettingClient {
|
export default interface SettingClient {
|
||||||
|
@ -10,6 +10,6 @@ export class SettingClientImpl {
|
||||||
let settings = await browser.runtime.sendMessage({
|
let settings = await browser.runtime.sendMessage({
|
||||||
type: messages.SETTINGS_QUERY,
|
type: messages.SETTINGS_QUERY,
|
||||||
});
|
});
|
||||||
return settings as Settings;
|
return valueOf(settings);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,16 +3,16 @@ import KeymapRepository from '../repositories/KeymapRepository';
|
||||||
import SettingRepository from '../repositories/SettingRepository';
|
import SettingRepository from '../repositories/SettingRepository';
|
||||||
import AddonEnabledRepository from '../repositories/AddonEnabledRepository';
|
import AddonEnabledRepository from '../repositories/AddonEnabledRepository';
|
||||||
import * as operations from '../../shared/operations';
|
import * as operations from '../../shared/operations';
|
||||||
import { Keymaps } from '../../shared/Settings';
|
|
||||||
import Key from '../domains/Key';
|
import Key from '../domains/Key';
|
||||||
import KeySequence from '../domains/KeySequence';
|
import KeySequence from '../domains/KeySequence';
|
||||||
|
import Keymaps from '../../shared/settings/Keymaps';
|
||||||
|
|
||||||
type KeymapEntityMap = Map<KeySequence, operations.Operation>;
|
type KeymapEntityMap = Map<KeySequence, operations.Operation>;
|
||||||
|
|
||||||
const reservedKeymaps: Keymaps = {
|
const reservedKeymaps = Keymaps.fromJSON({
|
||||||
'<Esc>': { type: operations.CANCEL },
|
'<Esc>': { type: operations.CANCEL },
|
||||||
'<C-[>': { type: operations.CANCEL },
|
'<C-[>': { type: operations.CANCEL },
|
||||||
};
|
});
|
||||||
|
|
||||||
@injectable()
|
@injectable()
|
||||||
export default class KeymapUseCase {
|
export default class KeymapUseCase {
|
||||||
|
@ -65,16 +65,11 @@ export default class KeymapUseCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
private keymapEntityMap(): KeymapEntityMap {
|
private keymapEntityMap(): KeymapEntityMap {
|
||||||
let keymaps = {
|
let keymaps = this.settingRepository.get().keymaps.combine(reservedKeymaps);
|
||||||
...this.settingRepository.get().keymaps,
|
let entries = keymaps.entries().map(entry => [
|
||||||
...reservedKeymaps,
|
|
||||||
};
|
|
||||||
let entries = Object.entries(keymaps).map((entry) => {
|
|
||||||
return [
|
|
||||||
KeySequence.fromMapKeys(entry[0]),
|
KeySequence.fromMapKeys(entry[0]),
|
||||||
entry[1],
|
entry[1],
|
||||||
];
|
]) as [KeySequence, operations.Operation][];
|
||||||
}) as [KeySequence, operations.Operation][];
|
|
||||||
return new Map<KeySequence, operations.Operation>(entries);
|
return new Map<KeySequence, operations.Operation>(entries);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import {
|
import {
|
||||||
JSONSettings, FormSettings, SettingSource,
|
JSONTextSettings, FormSettings, SettingSource,
|
||||||
} from '../../shared/SettingData';
|
} from '../../shared/SettingData';
|
||||||
|
|
||||||
// Settings
|
// Settings
|
||||||
|
@ -11,14 +11,14 @@ export const SETTING_SWITCH_TO_JSON = 'setting.switch.to.json';
|
||||||
interface SettingSetSettingsAcion {
|
interface SettingSetSettingsAcion {
|
||||||
type: typeof SETTING_SET_SETTINGS;
|
type: typeof SETTING_SET_SETTINGS;
|
||||||
source: SettingSource;
|
source: SettingSource;
|
||||||
json?: JSONSettings;
|
json?: JSONTextSettings;
|
||||||
form?: FormSettings;
|
form?: FormSettings;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface SettingShowErrorAction {
|
interface SettingShowErrorAction {
|
||||||
type: typeof SETTING_SHOW_ERROR;
|
type: typeof SETTING_SHOW_ERROR;
|
||||||
error: string;
|
error: string;
|
||||||
json: JSONSettings;
|
json: JSONTextSettings;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface SettingSwitchToFormAction {
|
interface SettingSwitchToFormAction {
|
||||||
|
@ -28,7 +28,7 @@ interface SettingSwitchToFormAction {
|
||||||
|
|
||||||
interface SettingSwitchToJsonAction {
|
interface SettingSwitchToJsonAction {
|
||||||
type: typeof SETTING_SWITCH_TO_JSON;
|
type: typeof SETTING_SWITCH_TO_JSON;
|
||||||
json: JSONSettings,
|
json: JSONTextSettings,
|
||||||
}
|
}
|
||||||
|
|
||||||
export type SettingAction =
|
export type SettingAction =
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import * as actions from './index';
|
import * as actions from './index';
|
||||||
import * as storages from '../storage';
|
import * as storages from '../storage';
|
||||||
import SettingData, {
|
import SettingData, {
|
||||||
JSONSettings, FormSettings, SettingSource,
|
JSONTextSettings, FormSettings, SettingSource,
|
||||||
} from '../../shared/SettingData';
|
} from '../../shared/SettingData';
|
||||||
|
|
||||||
const load = async(): Promise<actions.SettingAction> => {
|
const load = async(): Promise<actions.SettingAction> => {
|
||||||
|
@ -26,7 +26,7 @@ const save = async(data: SettingData): Promise<actions.SettingAction> => {
|
||||||
return set(data);
|
return set(data);
|
||||||
};
|
};
|
||||||
|
|
||||||
const switchToForm = (json: JSONSettings): actions.SettingAction => {
|
const switchToForm = (json: JSONTextSettings): actions.SettingAction => {
|
||||||
try {
|
try {
|
||||||
// toSettings exercise validation
|
// toSettings exercise validation
|
||||||
let form = FormSettings.fromSettings(json.toSettings());
|
let form = FormSettings.fromSettings(json.toSettings());
|
||||||
|
@ -44,7 +44,7 @@ const switchToForm = (json: JSONSettings): actions.SettingAction => {
|
||||||
};
|
};
|
||||||
|
|
||||||
const switchToJson = (form: FormSettings): actions.SettingAction => {
|
const switchToJson = (form: FormSettings): actions.SettingAction => {
|
||||||
let json = JSONSettings.fromSettings(form.toSettings());
|
let json = JSONTextSettings.fromSettings(form.toSettings());
|
||||||
return {
|
return {
|
||||||
type: actions.SETTING_SWITCH_TO_JSON,
|
type: actions.SETTING_SWITCH_TO_JSON,
|
||||||
json,
|
json,
|
||||||
|
|
|
@ -8,7 +8,7 @@ import BlacklistForm from './form/BlacklistForm';
|
||||||
import PropertiesForm from './form/PropertiesForm';
|
import PropertiesForm from './form/PropertiesForm';
|
||||||
import * as settingActions from '../../settings/actions/setting';
|
import * as settingActions from '../../settings/actions/setting';
|
||||||
import SettingData, {
|
import SettingData, {
|
||||||
JSONSettings, FormKeymaps, FormSearch, FormSettings,
|
JSONTextSettings, FormKeymaps, FormSearch, FormSettings,
|
||||||
} from '../../shared/SettingData';
|
} from '../../shared/SettingData';
|
||||||
import { State as AppState } from '../reducers/setting';
|
import { State as AppState } from '../reducers/setting';
|
||||||
import * as settings from '../../shared/Settings';
|
import * as settings from '../../shared/Settings';
|
||||||
|
@ -75,7 +75,7 @@ class SettingsComponent extends React.Component<Props> {
|
||||||
</div>;
|
</div>;
|
||||||
}
|
}
|
||||||
|
|
||||||
renderJsonFields(json: JSONSettings, error: string) {
|
renderJsonFields(json: JSONTextSettings, error: string) {
|
||||||
return <div>
|
return <div>
|
||||||
<Input
|
<Input
|
||||||
type='textarea'
|
type='textarea'
|
||||||
|
@ -85,7 +85,7 @@ class SettingsComponent extends React.Component<Props> {
|
||||||
error={error}
|
error={error}
|
||||||
onValueChange={this.bindJson.bind(this)}
|
onValueChange={this.bindJson.bind(this)}
|
||||||
onBlur={this.save.bind(this)}
|
onBlur={this.save.bind(this)}
|
||||||
value={json.toJSON()}
|
value={json.toJSONText()}
|
||||||
/>
|
/>
|
||||||
</div>;
|
</div>;
|
||||||
}
|
}
|
||||||
|
@ -97,7 +97,7 @@ class SettingsComponent extends React.Component<Props> {
|
||||||
fields = this.renderFormFields(this.props.form);
|
fields = this.renderFormFields(this.props.form);
|
||||||
} else if (this.props.source === 'json') {
|
} else if (this.props.source === 'json') {
|
||||||
fields = this.renderJsonFields(
|
fields = this.renderJsonFields(
|
||||||
this.props.json as JSONSettings, this.props.error);
|
this.props.json as JSONTextSettings, this.props.error);
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
|
@ -165,7 +165,7 @@ class SettingsComponent extends React.Component<Props> {
|
||||||
bindJson(_name: string, value: string) {
|
bindJson(_name: string, value: string) {
|
||||||
let data = new SettingData({
|
let data = new SettingData({
|
||||||
source: this.props.source,
|
source: this.props.source,
|
||||||
json: JSONSettings.valueOf(value),
|
json: JSONTextSettings.fromText(value),
|
||||||
});
|
});
|
||||||
this.props.dispatch(settingActions.set(data));
|
this.props.dispatch(settingActions.set(data));
|
||||||
}
|
}
|
||||||
|
@ -183,7 +183,7 @@ class SettingsComponent extends React.Component<Props> {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.props.dispatch(
|
this.props.dispatch(
|
||||||
settingActions.switchToForm(this.props.json as JSONSettings));
|
settingActions.switchToForm(this.props.json as JSONTextSettings));
|
||||||
this.save();
|
this.save();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,18 +1,18 @@
|
||||||
import * as actions from '../actions';
|
import * as actions from '../actions';
|
||||||
import {
|
import {
|
||||||
JSONSettings, FormSettings, SettingSource,
|
JSONTextSettings, FormSettings, SettingSource,
|
||||||
} from '../../shared/SettingData';
|
} from '../../shared/SettingData';
|
||||||
|
|
||||||
export interface State {
|
export interface State {
|
||||||
source: SettingSource;
|
source: SettingSource;
|
||||||
json?: JSONSettings;
|
json?: JSONTextSettings;
|
||||||
form?: FormSettings;
|
form?: FormSettings;
|
||||||
error: string;
|
error: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const defaultState: State = {
|
const defaultState: State = {
|
||||||
source: SettingSource.JSON,
|
source: SettingSource.JSON,
|
||||||
json: JSONSettings.valueOf(''),
|
json: JSONTextSettings.fromText(''),
|
||||||
error: '',
|
error: '',
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import * as operations from './operations';
|
import * as operations from './operations';
|
||||||
import Settings, * as settings from './Settings';
|
import Settings, * as settings from './Settings';
|
||||||
|
import Keymaps from './settings/Keymaps';
|
||||||
|
|
||||||
export class FormKeymaps {
|
export class FormKeymaps {
|
||||||
private data: {[op: string]: string};
|
private data: {[op: string]: string};
|
||||||
|
@ -8,8 +9,8 @@ export class FormKeymaps {
|
||||||
this.data = data;
|
this.data = data;
|
||||||
}
|
}
|
||||||
|
|
||||||
toKeymaps(): settings.Keymaps {
|
toKeymaps(): Keymaps {
|
||||||
let keymaps: settings.Keymaps = {};
|
let keymaps: { [key: string]: operations.Operation } = {};
|
||||||
for (let name of Object.keys(this.data)) {
|
for (let name of Object.keys(this.data)) {
|
||||||
let [type, argStr] = name.split('?');
|
let [type, argStr] = name.split('?');
|
||||||
let args = {};
|
let args = {};
|
||||||
|
@ -19,7 +20,7 @@ export class FormKeymaps {
|
||||||
let key = this.data[name];
|
let key = this.data[name];
|
||||||
keymaps[key] = operations.valueOf({ type, ...args });
|
keymaps[key] = operations.valueOf({ type, ...args });
|
||||||
}
|
}
|
||||||
return keymaps;
|
return Keymaps.fromJSON(keymaps);
|
||||||
}
|
}
|
||||||
|
|
||||||
toJSON(): {[op: string]: string} {
|
toJSON(): {[op: string]: string} {
|
||||||
|
@ -42,10 +43,11 @@ export class FormKeymaps {
|
||||||
return new FormKeymaps(data);
|
return new FormKeymaps(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
static fromKeymaps(keymaps: settings.Keymaps): FormKeymaps {
|
static fromKeymaps(keymaps: Keymaps): FormKeymaps {
|
||||||
|
let json = keymaps.toJSON();
|
||||||
let data: {[op: string]: string} = {};
|
let data: {[op: string]: string} = {};
|
||||||
for (let key of Object.keys(keymaps)) {
|
for (let key of Object.keys(json)) {
|
||||||
let op = keymaps[key];
|
let op = json[key];
|
||||||
let args = { ...op };
|
let args = { ...op };
|
||||||
delete args.type;
|
delete args.type;
|
||||||
|
|
||||||
|
@ -109,27 +111,32 @@ export class FormSearch {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class JSONSettings {
|
export class JSONTextSettings {
|
||||||
private json: string;
|
constructor(
|
||||||
|
private json: string,
|
||||||
constructor(json: any) {
|
) {
|
||||||
this.json = json;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
toSettings(): Settings {
|
toSettings(): Settings {
|
||||||
return settings.valueOf(JSON.parse(this.json));
|
return settings.valueOf(JSON.parse(this.json));
|
||||||
}
|
}
|
||||||
|
|
||||||
toJSON(): string {
|
toJSONText(): string {
|
||||||
return this.json;
|
return this.json;
|
||||||
}
|
}
|
||||||
|
|
||||||
static valueOf(o: ReturnType<JSONSettings['toJSON']>): JSONSettings {
|
static fromText(o: string): JSONTextSettings {
|
||||||
return new JSONSettings(o);
|
return new JSONTextSettings(o);
|
||||||
}
|
}
|
||||||
|
|
||||||
static fromSettings(data: Settings): JSONSettings {
|
static fromSettings(data: Settings): JSONTextSettings {
|
||||||
return new JSONSettings(JSON.stringify(data, undefined, 2));
|
let json = {
|
||||||
|
keymaps: data.keymaps.toJSON(),
|
||||||
|
search: data.search,
|
||||||
|
properties: data.properties,
|
||||||
|
blacklist: data.blacklist,
|
||||||
|
};
|
||||||
|
return new JSONTextSettings(JSON.stringify(json, undefined, 2));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -192,7 +199,7 @@ export class FormSettings {
|
||||||
|
|
||||||
toSettings(): Settings {
|
toSettings(): Settings {
|
||||||
return settings.valueOf({
|
return settings.valueOf({
|
||||||
keymaps: this.keymaps.toKeymaps(),
|
keymaps: this.keymaps.toKeymaps().toJSON(),
|
||||||
search: this.search.toSearchSettings(),
|
search: this.search.toSearchSettings(),
|
||||||
properties: this.properties,
|
properties: this.properties,
|
||||||
blacklist: this.blacklist,
|
blacklist: this.blacklist,
|
||||||
|
@ -244,7 +251,7 @@ export enum SettingSource {
|
||||||
export default class SettingData {
|
export default class SettingData {
|
||||||
private source: SettingSource;
|
private source: SettingSource;
|
||||||
|
|
||||||
private json?: JSONSettings;
|
private json?: JSONTextSettings;
|
||||||
|
|
||||||
private form?: FormSettings;
|
private form?: FormSettings;
|
||||||
|
|
||||||
|
@ -252,7 +259,7 @@ export default class SettingData {
|
||||||
source, json, form
|
source, json, form
|
||||||
}: {
|
}: {
|
||||||
source: SettingSource,
|
source: SettingSource,
|
||||||
json?: JSONSettings,
|
json?: JSONTextSettings,
|
||||||
form?: FormSettings,
|
form?: FormSettings,
|
||||||
}) {
|
}) {
|
||||||
this.source = source;
|
this.source = source;
|
||||||
|
@ -264,7 +271,7 @@ export default class SettingData {
|
||||||
return this.source;
|
return this.source;
|
||||||
}
|
}
|
||||||
|
|
||||||
getJSON(): JSONSettings {
|
getJSON(): JSONTextSettings {
|
||||||
if (!this.json) {
|
if (!this.json) {
|
||||||
throw new TypeError('json settings not set');
|
throw new TypeError('json settings not set');
|
||||||
}
|
}
|
||||||
|
@ -283,7 +290,7 @@ export default class SettingData {
|
||||||
case SettingSource.JSON:
|
case SettingSource.JSON:
|
||||||
return {
|
return {
|
||||||
source: this.source,
|
source: this.source,
|
||||||
json: (this.json as JSONSettings).toJSON(),
|
json: (this.json as JSONTextSettings).toJSONText(),
|
||||||
};
|
};
|
||||||
case SettingSource.Form:
|
case SettingSource.Form:
|
||||||
return {
|
return {
|
||||||
|
@ -313,8 +320,8 @@ export default class SettingData {
|
||||||
case SettingSource.JSON:
|
case SettingSource.JSON:
|
||||||
return new SettingData({
|
return new SettingData({
|
||||||
source: o.source,
|
source: o.source,
|
||||||
json: JSONSettings.valueOf(
|
json: JSONTextSettings.fromText(
|
||||||
o.json as ReturnType<JSONSettings['toJSON']>),
|
o.json as ReturnType<JSONTextSettings['toJSONText']>),
|
||||||
});
|
});
|
||||||
case SettingSource.Form:
|
case SettingSource.Form:
|
||||||
return new SettingData({
|
return new SettingData({
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
import * as operations from './operations';
|
|
||||||
import * as PropertyDefs from './property-defs';
|
import * as PropertyDefs from './property-defs';
|
||||||
|
import Keymaps from './settings/Keymaps';
|
||||||
export type Keymaps = {[key: string]: operations.Operation};
|
|
||||||
|
|
||||||
export interface Search {
|
export interface Search {
|
||||||
default: string;
|
default: string;
|
||||||
|
@ -21,14 +19,6 @@ export default interface Settings {
|
||||||
blacklist: string[];
|
blacklist: string[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export const keymapsValueOf = (o: any): Keymaps => {
|
|
||||||
return Object.keys(o).reduce((keymaps: Keymaps, key: string): Keymaps => {
|
|
||||||
let op = operations.valueOf(o[key]);
|
|
||||||
keymaps[key] = op;
|
|
||||||
return keymaps;
|
|
||||||
}, {});
|
|
||||||
};
|
|
||||||
|
|
||||||
export const searchValueOf = (o: any): Search => {
|
export const searchValueOf = (o: any): Search => {
|
||||||
if (typeof o.default !== 'string') {
|
if (typeof o.default !== 'string') {
|
||||||
throw new TypeError('string field "default" not set"');
|
throw new TypeError('string field "default" not set"');
|
||||||
|
@ -97,7 +87,7 @@ export const valueOf = (o: any): Settings => {
|
||||||
for (let key of Object.keys(o)) {
|
for (let key of Object.keys(o)) {
|
||||||
switch (key) {
|
switch (key) {
|
||||||
case 'keymaps':
|
case 'keymaps':
|
||||||
settings.keymaps = keymapsValueOf(o.keymaps);
|
settings.keymaps = Keymaps.fromJSON(o.keymaps);
|
||||||
break;
|
break;
|
||||||
case 'search':
|
case 'search':
|
||||||
settings.search = searchValueOf(o.search);
|
settings.search = searchValueOf(o.search);
|
||||||
|
@ -115,8 +105,17 @@ export const valueOf = (o: any): Settings => {
|
||||||
return settings;
|
return settings;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const toJSON = (settings: Settings): any => {
|
||||||
|
return {
|
||||||
|
keymaps: settings.keymaps.toJSON(),
|
||||||
|
search: settings.search,
|
||||||
|
properties: settings.properties,
|
||||||
|
blacklist: settings.blacklist,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
export const DefaultSetting: Settings = {
|
export const DefaultSetting: Settings = {
|
||||||
keymaps: {
|
keymaps: Keymaps.fromJSON({
|
||||||
'0': { 'type': 'scroll.home' },
|
'0': { 'type': 'scroll.home' },
|
||||||
':': { 'type': 'command.show' },
|
':': { 'type': 'command.show' },
|
||||||
'o': { 'type': 'command.show.open', 'alter': false },
|
'o': { 'type': 'command.show.open', 'alter': false },
|
||||||
|
@ -179,7 +178,7 @@ export const DefaultSetting: Settings = {
|
||||||
'N': { 'type': 'find.prev' },
|
'N': { 'type': 'find.prev' },
|
||||||
'.': { 'type': 'repeat.last' },
|
'.': { 'type': 'repeat.last' },
|
||||||
'<S-Esc>': { 'type': 'addon.toggle.enabled' }
|
'<S-Esc>': { 'type': 'addon.toggle.enabled' }
|
||||||
},
|
}),
|
||||||
search: {
|
search: {
|
||||||
default: 'google',
|
default: 'google',
|
||||||
engines: {
|
engines: {
|
||||||
|
|
37
src/shared/settings/Keymaps.ts
Normal file
37
src/shared/settings/Keymaps.ts
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
import * as operations from '../operations';
|
||||||
|
|
||||||
|
export type KeymapsJSON = { [key: string]: operations.Operation };
|
||||||
|
|
||||||
|
export default class Keymaps {
|
||||||
|
constructor(
|
||||||
|
private readonly data: KeymapsJSON,
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
|
static fromJSON(json: any): Keymaps {
|
||||||
|
if (typeof json !== 'object' || json === null) {
|
||||||
|
throw new TypeError('invalid keymaps type: ' + JSON.stringify(json));
|
||||||
|
}
|
||||||
|
|
||||||
|
let data: KeymapsJSON = {};
|
||||||
|
for (let key of Object.keys(json)) {
|
||||||
|
data[key] = operations.valueOf(json[key]);
|
||||||
|
}
|
||||||
|
return new Keymaps(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
combine(other: Keymaps): Keymaps {
|
||||||
|
return new Keymaps({
|
||||||
|
...this.data,
|
||||||
|
...other.data,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
toJSON(): KeymapsJSON {
|
||||||
|
return this.data;
|
||||||
|
}
|
||||||
|
|
||||||
|
entries(): [string, operations.Operation][] {
|
||||||
|
return Object.entries(this.data);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,12 +1,13 @@
|
||||||
import { SettingRepositoryImpl } from '../../../src/content/repositories/SettingRepository';
|
import { SettingRepositoryImpl } from '../../../src/content/repositories/SettingRepository';
|
||||||
import { expect } from 'chai';
|
import { expect } from 'chai';
|
||||||
|
import Keymaps from '../../../src/shared/settings/Keymaps';
|
||||||
|
|
||||||
describe('SettingRepositoryImpl', () => {
|
describe('SettingRepositoryImpl', () => {
|
||||||
it('updates and gets current value', () => {
|
it('updates and gets current value', () => {
|
||||||
let sut = new SettingRepositoryImpl();
|
let sut = new SettingRepositoryImpl();
|
||||||
|
|
||||||
let settings = {
|
let settings = {
|
||||||
keymaps: {},
|
keymaps: Keymaps.fromJSON({}),
|
||||||
search: {
|
search: {
|
||||||
default: 'google',
|
default: 'google',
|
||||||
engines: {
|
engines: {
|
||||||
|
@ -19,7 +20,7 @@ describe('SettingRepositoryImpl', () => {
|
||||||
complete: 'sbh',
|
complete: 'sbh',
|
||||||
},
|
},
|
||||||
blacklist: [],
|
blacklist: [],
|
||||||
}
|
};
|
||||||
|
|
||||||
sut.set(settings);
|
sut.set(settings);
|
||||||
|
|
||||||
|
@ -27,4 +28,3 @@ describe('SettingRepositoryImpl', () => {
|
||||||
expect(actual.properties.hintchars).to.equal('abcd1234');
|
expect(actual.properties.hintchars).to.equal('abcd1234');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
import SettingData, {
|
import SettingData, {
|
||||||
FormKeymaps, JSONSettings, FormSettings,
|
FormKeymaps, JSONTextSettings, FormSettings,
|
||||||
} from '../../src/shared/SettingData';
|
} from '../../src/shared/SettingData';
|
||||||
import Settings, { Keymaps } from '../../src/shared/Settings';
|
import Settings from '../../src/shared/Settings';
|
||||||
import { expect } from 'chai';
|
import { expect } from 'chai';
|
||||||
|
import Keymaps from '../../src/shared/settings/Keymaps';
|
||||||
|
|
||||||
describe('shared/SettingData', () => {
|
describe('shared/SettingData', () => {
|
||||||
describe('FormKeymaps', () => {
|
describe('FormKeymaps', () => {
|
||||||
|
@ -11,9 +12,9 @@ describe('shared/SettingData', () => {
|
||||||
let data = {
|
let data = {
|
||||||
'scroll.vertically?{"count":1}': 'j',
|
'scroll.vertically?{"count":1}': 'j',
|
||||||
'scroll.home': '0',
|
'scroll.home': '0',
|
||||||
}
|
};
|
||||||
|
|
||||||
let keymaps = FormKeymaps.valueOf(data).toKeymaps();
|
let keymaps = FormKeymaps.valueOf(data).toKeymaps().toJSON();
|
||||||
expect(keymaps).to.deep.equal({
|
expect(keymaps).to.deep.equal({
|
||||||
'j': { type: 'scroll.vertically', count: 1 },
|
'j': { type: 'scroll.vertically', count: 1 },
|
||||||
'0': { type: 'scroll.home' },
|
'0': { type: 'scroll.home' },
|
||||||
|
@ -23,13 +24,13 @@ describe('shared/SettingData', () => {
|
||||||
|
|
||||||
describe('#fromKeymaps to #toJSON', () => {
|
describe('#fromKeymaps to #toJSON', () => {
|
||||||
it('create from a Keymaps and create a JSON object', () => {
|
it('create from a Keymaps and create a JSON object', () => {
|
||||||
let data: Keymaps = {
|
let keymaps: Keymaps = Keymaps.fromJSON({
|
||||||
'j': { type: 'scroll.vertically', count: 1 },
|
'j': { type: 'scroll.vertically', count: 1 },
|
||||||
'0': { type: 'scroll.home' },
|
'0': { type: 'scroll.home' },
|
||||||
}
|
});
|
||||||
|
|
||||||
let keymaps = FormKeymaps.fromKeymaps(data).toJSON();
|
let form = FormKeymaps.fromKeymaps(keymaps).toJSON();
|
||||||
expect(keymaps).to.deep.equal({
|
expect(form).to.deep.equal({
|
||||||
'scroll.vertically?{"count":1}': 'j',
|
'scroll.vertically?{"count":1}': 'j',
|
||||||
'scroll.home': '0',
|
'scroll.home': '0',
|
||||||
});
|
});
|
||||||
|
@ -56,15 +57,20 @@ describe('shared/SettingData', () => {
|
||||||
"blacklist": []
|
"blacklist": []
|
||||||
}`;
|
}`;
|
||||||
|
|
||||||
let settings = JSONSettings.valueOf(o).toSettings();
|
let settings = JSONTextSettings.fromText(o).toSettings();
|
||||||
expect(settings).to.deep.equal(JSON.parse(o));
|
expect({
|
||||||
|
keymaps: settings.keymaps.toJSON(),
|
||||||
|
search: settings.search,
|
||||||
|
properties: settings.properties,
|
||||||
|
blacklist: settings.blacklist,
|
||||||
|
}).to.deep.equal(JSON.parse(o));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('#fromSettings to #toJSON', () => {
|
describe('#fromSettings to #toJSON', () => {
|
||||||
it('create from a Settings and create a JSON string', () => {
|
it('create from a Settings and create a JSON string', () => {
|
||||||
let o = {
|
let o = {
|
||||||
keymaps: {},
|
keymaps: Keymaps.fromJSON({}),
|
||||||
search: {
|
search: {
|
||||||
default: "google",
|
default: "google",
|
||||||
engines: {
|
engines: {
|
||||||
|
@ -79,8 +85,13 @@ describe('shared/SettingData', () => {
|
||||||
blacklist: [],
|
blacklist: [],
|
||||||
};
|
};
|
||||||
|
|
||||||
let json = JSONSettings.fromSettings(o).toJSON();
|
let json = JSONTextSettings.fromSettings(o).toJSONText();
|
||||||
expect(JSON.parse(json)).to.deep.equal(o);
|
expect(JSON.parse(json)).to.deep.equal({
|
||||||
|
keymaps: o.keymaps.toJSON(),
|
||||||
|
search: o.search,
|
||||||
|
properties: o.properties,
|
||||||
|
blacklist: o.blacklist,
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -108,7 +119,12 @@ describe('shared/SettingData', () => {
|
||||||
};
|
};
|
||||||
|
|
||||||
let settings = FormSettings.valueOf(data).toSettings();
|
let settings = FormSettings.valueOf(data).toSettings();
|
||||||
expect(settings).to.deep.equal({
|
expect({
|
||||||
|
keymaps: settings.keymaps.toJSON(),
|
||||||
|
search: settings.search,
|
||||||
|
properties: settings.properties,
|
||||||
|
blacklist: settings.blacklist,
|
||||||
|
}).to.deep.equal({
|
||||||
keymaps: {
|
keymaps: {
|
||||||
'j': { type: 'scroll.vertically', count: 1 },
|
'j': { type: 'scroll.vertically', count: 1 },
|
||||||
'0': { type: 'scroll.home' },
|
'0': { type: 'scroll.home' },
|
||||||
|
@ -132,10 +148,10 @@ describe('shared/SettingData', () => {
|
||||||
describe('#fromSettings to #toJSON', () => {
|
describe('#fromSettings to #toJSON', () => {
|
||||||
it('create from a Settings and create a JSON string', () => {
|
it('create from a Settings and create a JSON string', () => {
|
||||||
let data: Settings = {
|
let data: Settings = {
|
||||||
keymaps: {
|
keymaps: Keymaps.fromJSON({
|
||||||
'j': { type: 'scroll.vertically', count: 1 },
|
'j': { type: 'scroll.vertically', count: 1 },
|
||||||
'0': { type: 'scroll.home' },
|
'0': { type: 'scroll.home' },
|
||||||
},
|
}),
|
||||||
search: {
|
search: {
|
||||||
default: "google",
|
default: "google",
|
||||||
engines: {
|
engines: {
|
||||||
|
|
|
@ -1,31 +1,7 @@
|
||||||
import * as settings from '../../src/shared/Settings';
|
import * as settings from '../../src/shared/Settings';
|
||||||
import { expect } from 'chai';
|
import {expect} from 'chai';
|
||||||
|
|
||||||
describe('Settings', () => {
|
describe('Settings', () => {
|
||||||
describe('#keymapsValueOf', () => {
|
|
||||||
it('returns empty object by empty settings', () => {
|
|
||||||
let keymaps = settings.keymapsValueOf({});
|
|
||||||
expect(keymaps).to.be.empty;
|
|
||||||
});
|
|
||||||
|
|
||||||
it('returns keymaps by valid settings', () => {
|
|
||||||
let keymaps = settings.keymapsValueOf({
|
|
||||||
k: { type: "scroll.vertically", count: -1 },
|
|
||||||
j: { type: "scroll.vertically", count: 1 },
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(keymaps['k']).to.deep.equal({ type: "scroll.vertically", count: -1 });
|
|
||||||
expect(keymaps['j']).to.deep.equal({ type: "scroll.vertically", count: 1 });
|
|
||||||
});
|
|
||||||
|
|
||||||
it('throws a TypeError by invalid settings', () => {
|
|
||||||
expect(() => settings.keymapsValueOf(null)).to.throw(TypeError);
|
|
||||||
expect(() => settings.keymapsValueOf({
|
|
||||||
k: { type: "invalid.operation" },
|
|
||||||
})).to.throw(TypeError);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('#searchValueOf', () => {
|
describe('#searchValueOf', () => {
|
||||||
it('returns search settings by valid settings', () => {
|
it('returns search settings by valid settings', () => {
|
||||||
let search = settings.searchValueOf({
|
let search = settings.searchValueOf({
|
||||||
|
@ -110,16 +86,6 @@ describe('Settings', () => {
|
||||||
complete: "sbh"
|
complete: "sbh"
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('throws a TypeError by invalid settings', () => {
|
|
||||||
expect(() => settings.keymapsValueOf(null)).to.throw(TypeError);
|
|
||||||
expect(() => settings.keymapsValueOf({
|
|
||||||
smoothscroll: 'false',
|
|
||||||
})).to.throw(TypeError);
|
|
||||||
expect(() => settings.keymapsValueOf({
|
|
||||||
unknown: 'xyz'
|
|
||||||
})).to.throw(TypeError);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('#blacklistValueOf', () => {
|
describe('#blacklistValueOf', () => {
|
||||||
|
@ -161,7 +127,12 @@ describe('Settings', () => {
|
||||||
"blacklist": []
|
"blacklist": []
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(x).to.deep.equal({
|
expect({
|
||||||
|
keymaps: x.keymaps.toJSON(),
|
||||||
|
search: x.search,
|
||||||
|
properties: x.properties,
|
||||||
|
blacklist: x.blacklist,
|
||||||
|
}).to.deep.equal({
|
||||||
keymaps: {},
|
keymaps: {},
|
||||||
search: {
|
search: {
|
||||||
default: "google",
|
default: "google",
|
||||||
|
@ -180,7 +151,7 @@ describe('Settings', () => {
|
||||||
|
|
||||||
it('sets default settings', () => {
|
it('sets default settings', () => {
|
||||||
let value = settings.valueOf({});
|
let value = settings.valueOf({});
|
||||||
expect(value.keymaps).to.not.be.empty;
|
expect(value.keymaps.toJSON()).to.not.be.empty;
|
||||||
expect(value.properties).to.not.be.empty;
|
expect(value.properties).to.not.be.empty;
|
||||||
expect(value.search.default).to.be.a('string');
|
expect(value.search.default).to.be.a('string');
|
||||||
expect(value.search.engines).to.be.an('object');
|
expect(value.search.engines).to.be.an('object');
|
||||||
|
|
66
test/shared/settings/Keymaps.test.ts
Normal file
66
test/shared/settings/Keymaps.test.ts
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
import Keymaps from '../../../src/shared/settings/Keymaps';
|
||||||
|
import { expect } from 'chai';
|
||||||
|
|
||||||
|
describe('Keymaps', () => {
|
||||||
|
describe('#valueOf', () => {
|
||||||
|
it('returns empty object by empty settings', () => {
|
||||||
|
let keymaps = Keymaps.fromJSON({}).toJSON();
|
||||||
|
expect(keymaps).to.be.empty;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns keymaps by valid settings', () => {
|
||||||
|
let keymaps = Keymaps.fromJSON({
|
||||||
|
k: { type: "scroll.vertically", count: -1 },
|
||||||
|
j: { type: "scroll.vertically", count: 1 },
|
||||||
|
}).toJSON();
|
||||||
|
|
||||||
|
expect(keymaps['k']).to.deep.equal({ type: "scroll.vertically", count: -1 });
|
||||||
|
expect(keymaps['j']).to.deep.equal({ type: "scroll.vertically", count: 1 });
|
||||||
|
});
|
||||||
|
|
||||||
|
it('throws a TypeError by invalid settings', () => {
|
||||||
|
expect(() => Keymaps.fromJSON(null)).to.throw(TypeError);
|
||||||
|
expect(() => Keymaps.fromJSON({
|
||||||
|
k: { type: "invalid.operation" },
|
||||||
|
})).to.throw(TypeError);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('#combine', () => {
|
||||||
|
it('returns combined keymaps', () => {
|
||||||
|
let keymaps = Keymaps.fromJSON({
|
||||||
|
k: { type: "scroll.vertically", count: -1 },
|
||||||
|
j: { type: "scroll.vertically", count: 1 },
|
||||||
|
}).combine(Keymaps.fromJSON({
|
||||||
|
n: { type: "find.next" },
|
||||||
|
N: { type: "find.prev" },
|
||||||
|
}));
|
||||||
|
|
||||||
|
let entries = keymaps.entries().sort(([name1], [name2]) => name1.localeCompare(name2));
|
||||||
|
expect(entries).deep.equals([
|
||||||
|
['j', { type: "scroll.vertically", count: 1 }],
|
||||||
|
['k', { type: "scroll.vertically", count: -1 }],
|
||||||
|
['n', { type: "find.next" }],
|
||||||
|
['N', { type: "find.prev" }],
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('overrides current keymaps', () => {
|
||||||
|
let keymaps = Keymaps.fromJSON({
|
||||||
|
k: { type: "scroll.vertically", count: -1 },
|
||||||
|
j: { type: "scroll.vertically", count: 1 },
|
||||||
|
}).combine(Keymaps.fromJSON({
|
||||||
|
n: { type: "find.next" },
|
||||||
|
j: { type: "find.prev" },
|
||||||
|
}));
|
||||||
|
|
||||||
|
let entries = keymaps.entries().sort(([name1], [name2]) => name1.localeCompare(name2));
|
||||||
|
expect(entries).deep.equals([
|
||||||
|
['j', { type: "find.prev" }],
|
||||||
|
['k', { type: "scroll.vertically", count: -1 }],
|
||||||
|
['n', { type: "find.next" }],
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
Reference in a new issue