diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml
deleted file mode 100644
index e90fcce..0000000
--- a/.github/FUNDING.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-# These are supported funding model platforms
-
-patreon: "100"
-liberapay: hundredrabbits
diff --git a/.nojekyll b/.nojekyll
deleted file mode 100644
index 8b13789..0000000
--- a/.nojekyll
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/cli b/cli
new file mode 100644
index 0000000..ce2b16d
Binary files /dev/null and b/cli differ
diff --git a/examples/basics/io.lisp b/examples/basics/io.lisp
new file mode 100644
index 0000000..4eeb500
--- /dev/null
+++ b/examples/basics/io.lisp
@@ -0,0 +1,2 @@
+(open "/home/dakedres/pictures/elex-hiram.png")
+(export "png" 1.0 "test")
\ No newline at end of file
diff --git a/logo.grid b/logo.grid
new file mode 100644
index 0000000..5dc5a27
--- /dev/null
+++ b/logo.grid
@@ -0,0 +1,125 @@
+{
+ "settings": {
+ "size": {
+ "width": 615,
+ "height": 480
+ }
+ },
+ "layers": [
+ [
+ {
+ "type": "line",
+ "vertices": [
+ {
+ "x": -90,
+ "y": 60
+ },
+ {
+ "x": -75,
+ "y": -135
+ }
+ ]
+ },
+ {
+ "type": "arc_r",
+ "vertices": [
+ {
+ "x": -60,
+ "y": -15
+ },
+ {
+ "x": -60,
+ "y": -15
+ },
+ {
+ "x": -180,
+ "y": 75
+ }
+ ]
+ },
+ {
+ "type": "arc_c",
+ "vertices": [
+ {
+ "x": -90,
+ "y": 135
+ },
+ {
+ "x": -180,
+ "y": 75
+ }
+ ]
+ },
+ {
+ "type": "line",
+ "vertices": [
+ {
+ "x": 30,
+ "y": 45
+ },
+ {
+ "x": -90,
+ "y": 60
+ }
+ ]
+ },
+ {
+ "type": "arc_r",
+ "vertices": [
+ {
+ "x": 30,
+ "y": 45
+ },
+ {
+ "x": -60,
+ "y": -15
+ }
+ ]
+ },
+ {
+ "type": "arc_c",
+ "vertices": [
+ {
+ "x": 30,
+ "y": 45
+ },
+ {
+ "x": -90,
+ "y": 135
+ }
+ ]
+ }
+ ],
+ [],
+ []
+ ],
+ "styles": [
+ {
+ "thickness": 4,
+ "strokeLinecap": "round",
+ "strokeLinejoin": "round",
+ "color": "#0a0a0a",
+ "fill": "none",
+ "mirror_style": 0,
+ "transform": "rotate(45)"
+ },
+ {
+ "thickness": 15,
+ "strokeLinecap": "round",
+ "strokeLinejoin": "round",
+ "color": "#4a4a4a",
+ "fill": "none",
+ "mirror_style": 0,
+ "transform": "rotate(45)"
+ },
+ {
+ "thickness": 15,
+ "strokeLinecap": "round",
+ "strokeLinejoin": "round",
+ "color": "#6a6a6a",
+ "fill": "none",
+ "mirror_style": 0,
+ "transform": "rotate(45)"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/logo.svg b/logo.svg
new file mode 100644
index 0000000..4043147
--- /dev/null
+++ b/logo.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/open.sh b/open.sh
index 13f8b75..0fc64a6 100755
--- a/open.sh
+++ b/open.sh
@@ -1,4 +1,3 @@
-localhost . -p 1616 &
$(command -v ungoogled-chromium ||\
-command -v chromium ||\
-command -v chrome) --new-window --app="http://localhost:1616/src/browser/index.html"
\ No newline at end of file
+ command -v chromium ||\
+ command -v chrome) --new-window --app="file://$PWD/src/browser/index.html"
\ No newline at end of file
diff --git a/src/browser/Device.js b/src/browser/Device.js
new file mode 100644
index 0000000..095f89a
--- /dev/null
+++ b/src/browser/Device.js
@@ -0,0 +1,50 @@
+import * as store from './Store.js'
+
+const noWorkingDirWarning = "Please open a directory to allow file saving."
+
+function Device() {
+ this.init = async () => {
+ await store.Init()
+ window.cwd = await store.Get('directory')
+ }
+
+ this.cd = async () => {
+ window.cwd = await window.showDirectoryPicker()
+ await store.Set('directory', window.cwd)
+ }
+
+ this.entries = async () => {
+ let pool = new Map()
+
+ for await (let [ , e ] of window.cwd.entries()) {
+ if(e instanceof FileSystemFileHandle) {
+ pool.set(e.name, e)
+ }
+ }
+
+ return pool
+ }
+
+ this.create = async (sPath) => {
+ return window.cwd.getFileHandle(sPath, { create: true })
+ }
+
+ this.open = async (hFile) => {
+ if(!window.cwd) {
+ return new Blob([ noWorkingDirWarning ], { type: "text/plain" })
+ }
+
+ return hFile.getFile()
+ }
+
+ this.write = async (hFile, sContent) => {
+ if(!window.cwd) {
+ throw new Error("Unable to save file: no working directory")
+ }
+
+ let s = await hFile.createWritable()
+ .catch(console.error)
+ await s.write(sContent)
+ await s.close()
+ }
+}
\ No newline at end of file
diff --git a/src/browser/Source.js b/src/browser/Source.js
index 1d1ef8f..696bf9a 100644
--- a/src/browser/Source.js
+++ b/src/browser/Source.js
@@ -1,97 +1,42 @@
function Source (client) {
- this.cache = {}
+ this.cwd = null
- this.install = () => {
- }
+ this.install = () => {
+ }
- this.start = () => {
- this.new()
- }
+ this.start = () => {
+ }
- this.new = () => {
- console.log('Source', 'New file..')
- this.cache = {}
- }
+ // I/O
- this.open = (ext, callback, store = false) => {
- console.log('Source', 'Open file..')
- const input = document.createElement('input')
- input.type = 'file'
- input.onchange = (e) => {
- const file = e.target.files[0]
- if (file.name.indexOf('.' + ext) < 0) { console.warn('Source', `Skipped ${file.name}`); return }
- this.read(file, callback, store)
- }
- input.click()
- }
+ this.read = (file, callback, store = false) => {
+ if(!this.cwd) {
+ openCwd()
+ }
- this.load = (ext, callback) => {
- console.log('Source', 'Load files..')
- const input = document.createElement('input')
- input.type = 'file'
- input.setAttribute('multiple', 'multiple')
- input.onchange = (e) => {
- for (const file of e.target.files) {
- if (file.name.indexOf('.' + ext) < 0) { console.warn('Source', `Skipped ${file.name}`); continue }
- this.read(file, this.store)
- }
- }
- input.click()
- }
+
+ }
- this.store = (file, content) => {
- console.info('Source', 'Stored ' + file.name)
- this.cache[file.name] = content
- }
+ this.write = (name, ext, content, type, settings = 'charset=utf-8') => {
- this.save = (name, content, type = 'text/plain', callback) => {
- this.saveAs(name, content, type, callback)
- }
+ }
- this.saveAs = (name, ext, content, type = 'text/plain', callback) => {
- console.log('Source', 'Save new file..')
- this.write(name, ext, content, type, callback)
- }
+ function timestamp (d = new Date(), e = new Date(d)) {
+ return `${arvelie()}-${neralie()}`
+ }
- // I/O
+ function arvelie (date = new Date()) {
+ const start = new Date(date.getFullYear(), 0, 0)
+ const diff = (date - start) + ((start.getTimezoneOffset() - date.getTimezoneOffset()) * 60 * 1000)
+ const doty = Math.floor(diff / 86400000) - 1
+ const y = date.getFullYear().toString().substr(2, 2)
+ const m = doty === 364 || doty === 365 ? '+' : String.fromCharCode(97 + Math.floor(doty / 14)).toUpperCase()
+ const d = `${(doty === 365 ? 1 : doty === 366 ? 2 : (doty % 14)) + 1}`.padStart(2, '0')
+ return `${y}${m}${d}`
+ }
- this.read = (file, callback, store = false) => {
- const reader = new FileReader()
- reader.onload = (event) => {
- const res = event.target.result
- if (callback) { callback(file, res) }
- if (store) { this.store(file, res) }
- }
- reader.readAsText(file, 'UTF-8')
- }
-
- this.write = (name, ext, content, type, settings = 'charset=utf-8') => {
- const link = document.createElement('a')
- link.setAttribute('download', `${name}-${timestamp()}.${ext}`)
- if (type === 'image/png' || type === 'image/jpeg') {
- link.setAttribute('href', content)
- } else {
- link.setAttribute('href', 'data:' + type + ';' + settings + ',' + encodeURIComponent(content))
- }
- link.dispatchEvent(new MouseEvent('click', { bubbles: true, cancelable: true, view: window }))
- }
-
- function timestamp (d = new Date(), e = new Date(d)) {
- return `${arvelie()}-${neralie()}`
- }
-
- function arvelie (date = new Date()) {
- const start = new Date(date.getFullYear(), 0, 0)
- const diff = (date - start) + ((start.getTimezoneOffset() - date.getTimezoneOffset()) * 60 * 1000)
- const doty = Math.floor(diff / 86400000) - 1
- const y = date.getFullYear().toString().substr(2, 2)
- const m = doty === 364 || doty === 365 ? '+' : String.fromCharCode(97 + Math.floor(doty / 14)).toUpperCase()
- const d = `${(doty === 365 ? 1 : doty === 366 ? 2 : (doty % 14)) + 1}`.padStart(2, '0')
- return `${y}${m}${d}`
- }
-
- function neralie (d = new Date(), e = new Date(d)) {
- const ms = e - d.setHours(0, 0, 0, 0)
- return (ms / 8640 / 10000).toFixed(6).substr(2, 6)
- }
+ function neralie (d = new Date(), e = new Date(d)) {
+ const ms = e - d.setHours(0, 0, 0, 0)
+ return (ms / 8640 / 10000).toFixed(6).substr(2, 6)
+ }
}
diff --git a/src/browser/Store.js b/src/browser/Store.js
new file mode 100644
index 0000000..b0bcbc8
--- /dev/null
+++ b/src/browser/Store.js
@@ -0,0 +1,47 @@
+function Store(objectStoreName) {
+ const transact = () => {
+ return this.db
+ .transaction(objectStoreName, "readwrite")
+ .objectStore(objectStoreName)
+ }
+
+ this.Get = (key) => {
+ return promisify(
+ transact().get(key)
+ )
+ }
+
+ this.Set = (key, value) => {
+ return promisify(
+ transact().put(value, key)
+ )
+ }
+
+ return this
+}
+
+Store.Open = async (dbName, objectStoreName) => {
+ let store = new Store(objectStoreName)
+ const request = indexedDB.open(dbName, 2)
+
+ request.onupgradeneeded = (event) => {
+ const db = event.target.result
+ const objectStore = db.createObjectStore(objectStoreName)
+
+ objectStore.createIndex('value', 'value', { unique: false })
+ }
+
+ store.db = await promisify(request)
+ return store
+}
+
+function promisify(request) {
+ return new Promise((resolve, reject) => {
+ request.onsuccess = (event) => {
+ resolve(request.result)
+ }
+ request.onerror = (event) => {
+ reject(request.error)
+ }
+ })
+}
\ No newline at end of file
diff --git a/src/browser/index.html b/src/browser/index.html
index 2b39764..7b74182 100644
--- a/src/browser/index.html
+++ b/src/browser/index.html
@@ -9,6 +9,7 @@
+
@@ -29,8 +30,12 @@
const client = new Client()
client.install(document.body)
-window.addEventListener('load', () => {
- client.start()
+window.addEventListener('load', () => {
+ Store.Open("lonin", "lonin")
+ .then(store => {
+ window.store = store
+ client.start()
+ })
})
diff --git a/test.png b/test.png
new file mode 100644
index 0000000..2855abb
Binary files /dev/null and b/test.png differ
diff --git a/yarn.lock b/yarn.lock
new file mode 100644
index 0000000..f03ef67
--- /dev/null
+++ b/yarn.lock
@@ -0,0 +1,63 @@
+# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
+# yarn lockfile v1
+
+
+"@napi-rs/canvas-android-arm64@0.1.52":
+ version "0.1.52"
+ resolved "https://registry.yarnpkg.com/@napi-rs/canvas-android-arm64/-/canvas-android-arm64-0.1.52.tgz#b0383c98d004e9f02ca71a8c2d68a49284b7f215"
+ integrity sha512-x/K471KbASPVh5mfBUxokza66J0FNIlOgMNANWAf5C8HiATb487KecEhSkUQvvTS3WLYC9uSqIPHFgwF+tir3w==
+
+"@napi-rs/canvas-darwin-arm64@0.1.52":
+ version "0.1.52"
+ resolved "https://registry.yarnpkg.com/@napi-rs/canvas-darwin-arm64/-/canvas-darwin-arm64-0.1.52.tgz#6f06e38d2ff12b4e8cb7dec593aa271d29cf41d5"
+ integrity sha512-4OgVRD7TW02q5Q7lWLLjT+pYJ9ZHkQUTBOuXbPQ5wB0Wnh3RIq/aMY6thoXDZDzdR5vV3a5TUtbZUJ0aqLq3NA==
+
+"@napi-rs/canvas-darwin-x64@0.1.52":
+ version "0.1.52"
+ resolved "https://registry.yarnpkg.com/@napi-rs/canvas-darwin-x64/-/canvas-darwin-x64-0.1.52.tgz#f3269e7dbda9f6f2f0245aae44df4a8ac9940574"
+ integrity sha512-3fgeGJ3j2X6Mtmn0QYf3iA+A6y1ePnsayakc2emEokzf03ErrPczONw3vjnTQo53JLPMzEnfPGAffdktU/ssPA==
+
+"@napi-rs/canvas-linux-arm-gnueabihf@0.1.52":
+ version "0.1.52"
+ resolved "https://registry.yarnpkg.com/@napi-rs/canvas-linux-arm-gnueabihf/-/canvas-linux-arm-gnueabihf-0.1.52.tgz#711d82f0d86d8d1570b4fd93bc0017490be552ff"
+ integrity sha512-aaDEEK5XwHUrPt0q4SR8l7Va0vtn50KmSs+itxP+o7RNk3Nuch8fINHOXyhMyhwNYgv1tfiJVyHsJhD0E6lXGA==
+
+"@napi-rs/canvas-linux-arm64-gnu@0.1.52":
+ version "0.1.52"
+ resolved "https://registry.yarnpkg.com/@napi-rs/canvas-linux-arm64-gnu/-/canvas-linux-arm64-gnu-0.1.52.tgz#fd59f5064cec550b01bd20e42e35886531dbd88a"
+ integrity sha512-tzuwM7Amt5mkrp4csQjYWkFzwFdiCm7RNdJ5usX8syzKSXmozqWzLHjzo/2ozdSQNUy6wyzRrxkG4Rh6g0OpOA==
+
+"@napi-rs/canvas-linux-arm64-musl@0.1.52":
+ version "0.1.52"
+ resolved "https://registry.yarnpkg.com/@napi-rs/canvas-linux-arm64-musl/-/canvas-linux-arm64-musl-0.1.52.tgz#cf097920b93c610c9b69305c7522d14cb2e970a3"
+ integrity sha512-HQCtJlDT0dFp3uUZVzZOZ1VLMO7lbLRc548MjMxPpojit2ZdGopFzJ8jDSr4iszHrTO1SM1AxPaCM3pRvCAtjw==
+
+"@napi-rs/canvas-linux-x64-gnu@0.1.52":
+ version "0.1.52"
+ resolved "https://registry.yarnpkg.com/@napi-rs/canvas-linux-x64-gnu/-/canvas-linux-x64-gnu-0.1.52.tgz#9a4e6b5d392d8f83477dbbb2067dc0e50785edbb"
+ integrity sha512-z5sBEw0PVWPH/MIQL8hOR8C3YYVlu8lqtRUcYajigMfXAhbMiNqDWTjuIWGMz3nIydDjZmn8KTxw/D4a0HFPqQ==
+
+"@napi-rs/canvas-linux-x64-musl@0.1.52":
+ version "0.1.52"
+ resolved "https://registry.yarnpkg.com/@napi-rs/canvas-linux-x64-musl/-/canvas-linux-x64-musl-0.1.52.tgz#10a035304876c8b75474c169208de29d05553165"
+ integrity sha512-G1+JdWFhHLyHhULJS51xTEhB7EL0ZiAUQwQaRi4/w75OOYDQ91O+o4miaxDHiV0hZuxBhHtZU6ftV2Zl3RMguw==
+
+"@napi-rs/canvas-win32-x64-msvc@0.1.52":
+ version "0.1.52"
+ resolved "https://registry.yarnpkg.com/@napi-rs/canvas-win32-x64-msvc/-/canvas-win32-x64-msvc-0.1.52.tgz#b9b4d71e8c06b65f838b6caf4e6c44b46fe5b16e"
+ integrity sha512-hMI626VsCC/wv29qHF78N7TSG+auatOp08DHln0Zdif5y1NJ14NU/rNUhzlTW8Zc6ssw+AMDJ3KKYYWYYg1aoA==
+
+"@napi-rs/canvas@^0.1.41":
+ version "0.1.52"
+ resolved "https://registry.yarnpkg.com/@napi-rs/canvas/-/canvas-0.1.52.tgz#49c3a27c9243ffa5b21ba6368155aad6252e180c"
+ integrity sha512-xeW9EghZLDPZuqWJ4l1+eG3ld0i9J7SpV2zlgi34MPt/FE9K2XWGCfnLr0gHGOBkcI3YOVhI13I0HqRAkMPdVw==
+ optionalDependencies:
+ "@napi-rs/canvas-android-arm64" "0.1.52"
+ "@napi-rs/canvas-darwin-arm64" "0.1.52"
+ "@napi-rs/canvas-darwin-x64" "0.1.52"
+ "@napi-rs/canvas-linux-arm-gnueabihf" "0.1.52"
+ "@napi-rs/canvas-linux-arm64-gnu" "0.1.52"
+ "@napi-rs/canvas-linux-arm64-musl" "0.1.52"
+ "@napi-rs/canvas-linux-x64-gnu" "0.1.52"
+ "@napi-rs/canvas-linux-x64-musl" "0.1.52"
+ "@napi-rs/canvas-win32-x64-msvc" "0.1.52"