From 219aebbf7dfbabc44619d4c6cec69cf0accf2d8d Mon Sep 17 00:00:00 2001 From: Ragg Date: Thu, 30 Aug 2018 18:14:14 +0900 Subject: [PATCH 1/3] Introduce msgpack5 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit msgpack5実装はいくつかあったけど、以下の理由でmsgpack5を使うことにした - msgpack-js-v5: Bufferを含むものをdecodeするとBufferではなく添字付きオブジェクトに変換されて型の意味が失われた、あとextを使ってundefinedに対応されてやめてくれになった - msgpack5: importしたのを()しないといけないのがなんかキモいけど、Bufferにちゃんと対応していたのと、変な拡張とかも入ってなくて素直だった --- packages/delir/package.json | 1 + yarn.lock | 18 +++++++++++++++++- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/packages/delir/package.json b/packages/delir/package.json index 8bbdcddd6..022050e44 100644 --- a/packages/delir/package.json +++ b/packages/delir/package.json @@ -34,6 +34,7 @@ "mkdirp-promise": "5.0.1", "monaco-editor": "0.14.3", "mouse-wheel": "1.2.0", + "msgpack5": "4.2.0", "node-timecodes": "2.4.1", "parse-color": "1.0.0", "react": "16.4.1", diff --git a/yarn.lock b/yarn.lock index a8560bb62..53b017688 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1468,6 +1468,13 @@ bindings@^1.2.1: version "1.3.0" resolved "https://registry.yarnpkg.com/bindings/-/bindings-1.3.0.tgz#b346f6ecf6a95f5a815c5839fc7cdb22502f1ed7" +bl@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/bl/-/bl-2.0.1.tgz#1de8346d50c3078d088d6a60c2bbc8c516248bc5" + dependencies: + readable-stream "^2.3.5" + safe-buffer "^5.1.1" + block-stream@*: version "0.0.9" resolved "https://registry.yarnpkg.com/block-stream/-/block-stream-0.0.9.tgz#13ebfe778a03205cfe03751481ebb4b3300c126a" @@ -5409,6 +5416,15 @@ ms@2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" +msgpack5@4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/msgpack5/-/msgpack5-4.2.0.tgz#e005ec893b71e1140bb177f2d1f4b7f290169611" + dependencies: + bl "^2.0.0" + inherits "^2.0.3" + readable-stream "^2.3.6" + safe-buffer "^5.1.2" + mute-stdout@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/mute-stdout/-/mute-stdout-1.0.0.tgz#5b32ea07eb43c9ded6130434cf926f46b2a7fd4d" @@ -6708,7 +6724,7 @@ readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable string_decoder "~1.0.0" util-deprecate "~1.0.1" -readable-stream@^2.0.6, readable-stream@^2.3.3, readable-stream@^2.3.5: +readable-stream@^2.0.6, readable-stream@^2.3.3, readable-stream@^2.3.5, readable-stream@^2.3.6: version "2.3.6" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.6.tgz#b11c27d88b8ff1fbe070643cf94b0c79ae1b0aaf" dependencies: From 971e5054089a1f80d114d2e51b233512ecdd504f Mon Sep 17 00:00:00 2001 From: Ragg Date: Thu, 30 Aug 2018 18:50:46 +0900 Subject: [PATCH 2/3] Support Expression serialization --- packages/delir-core/src/project/keyframe.ts | 4 ++++ packages/delir-core/src/project/scheme/keyframe.ts | 2 ++ packages/delir-core/src/values/expression.ts | 4 ++++ 3 files changed, 10 insertions(+) diff --git a/packages/delir-core/src/project/keyframe.ts b/packages/delir-core/src/project/keyframe.ts index 3f80d1386..5b10cfc93 100644 --- a/packages/delir-core/src/project/keyframe.ts +++ b/packages/delir-core/src/project/keyframe.ts @@ -39,6 +39,8 @@ export default class Keyframe realValue = ColorRGBA.fromJSON(jsonValue.value) } else if (jsonValue.type === 'asset') { realValue = jsonValue.value + } else if (jsonValue.type === 'expression') { + realValue = Expression.fromJSON(jsonValue.value) } else { const __NEVER__: never = jsonValue throw new Error(`Deserialization failed, unexpected object value on Keyframe#${keyframeJson.id}`) @@ -110,6 +112,8 @@ export default class Keyframe value = { type: 'color-rgba', value: this.value.toJSON() } } else if (_.isObject(this.value) && _.has(this.value as AssetPointerScheme, 'assetId')) { value = { type: 'asset', value: toJSON(this.value as AssetPointerScheme) } + } else if (_.isObject(this.value) && this.value instanceof Expression) { + value = { type: 'expression', value: this.value.toJSON() } } else if (_.isObject(this.value)) { throw new Error(`Serialization failed, unexpected value type on Keyframe#${this.id}`) } else { diff --git a/packages/delir-core/src/project/scheme/keyframe.ts b/packages/delir-core/src/project/scheme/keyframe.ts index cacc671a7..00a624917 100644 --- a/packages/delir-core/src/project/scheme/keyframe.ts +++ b/packages/delir-core/src/project/scheme/keyframe.ts @@ -4,6 +4,7 @@ // import Size3D from '../../values/size-3d' import { ColorRgbJSON } from '../../values/color-rgb' import { ColorRgbaJSON } from '../../values/color-rgba' +import { ExpressionJSON } from '../../values/expression' export interface AssetPointerScheme { assetId: string @@ -16,6 +17,7 @@ export type JSONKeyframeValueTypes = | {type: 'color-rgb', value: ColorRgbJSON} | {type: 'color-rgba', value: ColorRgbaJSON} | {type: 'asset', value: AssetPointerScheme} + | {type: 'expression', value: ExpressionJSON} // Point2D|Point3D|Size2D|Size3D export interface KeyframeConfigScheme { diff --git a/packages/delir-core/src/values/expression.ts b/packages/delir-core/src/values/expression.ts index a8a0e8ebb..82353e4ae 100644 --- a/packages/delir-core/src/values/expression.ts +++ b/packages/delir-core/src/values/expression.ts @@ -4,6 +4,10 @@ export interface ExpressionJSON { } export default class Expression { + public static fromJSON(json: ExpressionJSON) { + return new Expression(json.language, json.code) + } + constructor( public language: string, public code: string, From 0e53bfff6da1ce52d009e559dc722825747020db Mon Sep 17 00:00:00 2001 From: Ragg Date: Thu, 30 Aug 2018 18:52:27 +0900 Subject: [PATCH 3/3] Project saving with msgpack MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ついでに obj.project にプロジェクト構造を吐くようにした。 これをすることで将来的に obj.editor にプロジェクトの状態を吐いたりできるようになる --- packages/delir/actions/App.ts | 56 ++++---------------- packages/delir/package.json | 1 + packages/delir/views/AppMenu/AppMenu.i18n.ts | 12 +++++ packages/delir/views/AppMenu/AppMenu.tsx | 41 +++++++++++++- yarn.lock | 12 +++++ 5 files changed, 75 insertions(+), 47 deletions(-) diff --git a/packages/delir/actions/App.ts b/packages/delir/actions/App.ts index 601e91023..c6338fef1 100644 --- a/packages/delir/actions/App.ts +++ b/packages/delir/actions/App.ts @@ -4,6 +4,7 @@ import { BSON } from 'bson' import { remote } from 'electron' import * as fs from 'fs-promise' import * as _ from 'lodash' +import * as MsgPack from 'msgpack5' import * as path from 'path' import EditorStateStore from '../stores/EditorStateStore' @@ -155,9 +156,8 @@ export const openProject = operation(async (context) => { if (!path.length) return - const projectBson = await fs.readFile(path[0]) - const projectJson = (new BSON()).deserialize(projectBson) - + const projectMpk = await fs.readFile(path[0]) + const projectJson = MsgPack().decode(projectMpk).project const migratedProject = Delir.ProjectMigrator.migrate(projectJson) await context.executeOperation(setActiveProject, { @@ -166,52 +166,16 @@ export const openProject = operation(async (context) => { }) }) -export const overwriteProject = operation(async (context) => { - const state = context.getStore(EditorStateStore).getState() - const { project, projectPath } = state - - if (!project) return - - if (!projectPath) { - await context.executeOperation(saveProject, {}) - return - } - - const bson = new BSON() - - await fs.writeFile(projectPath, bson.serialize(project.toPreBSON())) - - await context.executeOperation(notify, { - message: 'Project saved', - title: '', - level: 'info', - timeout: 1000 - }) -}) - -export const saveProject = operation(async (context) => { +export const saveProject = operation(async (context, { path, silent = false }: { path: string, silent: boolean }) => { const project = context.getStore(EditorStateStore).getState().project if (!project) return - const path = remote.dialog.showSaveDialog({ - title: 'Save as ...', - buttonLabel: 'Save', - filters: [ - { - name: 'Delir Project File', - extensions: ['delir'] - } - ], - }) - - if (!path) return - - const bson = new BSON() - await fs.writeFile(path, bson.serialize(project.toPreBSON())) + await fs.writeFile(path, MsgPack().encode({ project: project.toPreBSON() })) context.executeOperation(setActiveProject, { project, path }) // update path - await context.executeOperation(notify, { + + !silent && await context.executeOperation(notify, { message: t('saved'), title: '', level: 'info', @@ -240,8 +204,8 @@ export const autoSaveProject = operation(async (context) => { const autoSaveFileName = `${frag.name}.auto-saved${frag.ext}` const autoSavePath = path.join(frag.dir, autoSaveFileName) - const bson = new BSON() - await fs.writeFile(autoSavePath, bson.serialize(project.toPreBSON())) + await context.executeOperation(saveProject, { path: autoSavePath, silent: true }) + context.executeOperation(notify, { message: t('autoSaved', { fileName: autoSaveFileName }), title: '', @@ -249,3 +213,5 @@ export const autoSaveProject = operation(async (context) => { timeout: 2000 }) }) + +console.log(MsgPack().encode({ a: 'b' })) diff --git a/packages/delir/package.json b/packages/delir/package.json index 022050e44..c159c1dd8 100644 --- a/packages/delir/package.json +++ b/packages/delir/package.json @@ -14,6 +14,7 @@ "@types/fs-promise": "1.0.3", "@types/keymirror": "0.1.1", "@types/lodash": "4.14.116", + "@types/msgpack5": "3.4.1", "@types/react": "16.4.12", "@types/react-color": "2.13.6", "@types/react-dom": "16.0.7", diff --git a/packages/delir/views/AppMenu/AppMenu.i18n.ts b/packages/delir/views/AppMenu/AppMenu.i18n.ts index 22f062bd2..5f5aa9539 100644 --- a/packages/delir/views/AppMenu/AppMenu.i18n.ts +++ b/packages/delir/views/AppMenu/AppMenu.i18n.ts @@ -37,6 +37,12 @@ export default I18n({ help: { label: 'ヘルプ', }, + modals: { + saveAs: { + title: '新しいファイルに保存', + save: '保存', + } + }, }, en: { appMenu: { @@ -74,5 +80,11 @@ export default I18n({ help: { label: 'Help', }, + modals: { + saveAs: { + title: 'Save as ...', + save: 'Save', + } + }, }, }) diff --git a/packages/delir/views/AppMenu/AppMenu.tsx b/packages/delir/views/AppMenu/AppMenu.tsx index 537e42b93..3bf33a297 100644 --- a/packages/delir/views/AppMenu/AppMenu.tsx +++ b/packages/delir/views/AppMenu/AppMenu.tsx @@ -81,12 +81,49 @@ export default withComponentContext(connectToStores([EditorStateStore], (context { label: t('file.save'), accelerator: 'CmdOrCtrl+S', - click: () => context.executeOperation(AppActions.overwriteProject, {}) + click: () => { + const state = context.getStore(EditorStateStore).getState() + let path: string | null = state.projectPath + + if (!path) { + path = remote.dialog.showSaveDialog({ + title: t('modals.saveAs.title'), + buttonLabel: t('modals.saveAs.save'), + filters: [ + { + name: 'Delir Project File', + extensions: ['delir'] + } + ], + }) + + // cancelled + if (!path) return + } + + context.executeOperation(AppActions.saveProject, { path }) + } }, { label: t('file.saveAs'), accelerator: 'CmdOrCtrl+Shift+S', - click: () => context.executeOperation(AppActions.saveProject, {}) + click: () => { + const path = remote.dialog.showSaveDialog({ + title: t('modals.saveAs.title'), + buttonLabel: t('modals.saveAs.save'), + filters: [ + { + name: 'Delir Project File', + extensions: ['delir'] + } + ], + }) + + // cancelled + if (!path) return + + context.executeOperation(AppActions.saveProject, { path }) + } }, {type: 'separator'}, { diff --git a/yarn.lock b/yarn.lock index 53b017688..507e227c4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -27,6 +27,12 @@ dependencies: any-observable "^0.3.0" +"@types/bl@*": + version "0.8.32" + resolved "https://registry.yarnpkg.com/@types/bl/-/bl-0.8.32.tgz#997d4332556c12eccae3bae93c0e6c0b53c562d4" + dependencies: + "@types/node" "*" + "@types/bson@1.0.11": version "1.0.11" resolved "https://registry.yarnpkg.com/@types/bson/-/bson-1.0.11.tgz#c95ad69bb0b3f5c33b4bb6cc86d86cafb273335c" @@ -83,6 +89,12 @@ version "5.2.5" resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-5.2.5.tgz#8a4accfc403c124a0bafe8a9fc61a05ec1032073" +"@types/msgpack5@3.4.1": + version "3.4.1" + resolved "https://registry.yarnpkg.com/@types/msgpack5/-/msgpack5-3.4.1.tgz#79a0bdf1a723abd8496b0dba380ee02a5e41264a" + dependencies: + "@types/bl" "*" + "@types/mz@*", "@types/mz@0.0.32": version "0.0.32" resolved "https://registry.yarnpkg.com/@types/mz/-/mz-0.0.32.tgz#e8248b4e41424c052edc1725dd33650c313a3659"