Introducing single config for prettier and applying it across the codebase. (#3141)

This commit is contained in:
Michał Wawrzyniec Urbańczyk 2021-11-05 12:51:43 +01:00 committed by GitHub
parent 22cefa7659
commit e18322e802
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
67 changed files with 1767 additions and 1681 deletions

View File

@ -13,5 +13,5 @@ distribution/lib/Standard/Database/*/THIRD-PARTY
built-distribution/
THIRD-PARTY
# GUI has its own config in the subdirectory.
gui/
gui/dist/
**/scala-parser.js

View File

@ -1,4 +0,0 @@
{
"printWidth": 80,
"proseWrap": "always"
}

View File

@ -1,5 +1,4 @@
overrides:
- files: "*.[j|t]s"
options:
printWidth: 100

View File

@ -1,10 +1,9 @@
---
name: Bug Report
about: Report a bug in Enso IDE.
title: ''
labels: 'Type: Bug'
assignees: ''
title: ""
labels: "Type: Bug"
assignees: ""
---
<!--
@ -13,22 +12,26 @@ the bug! It may have been fixed since.
-->
### What did you do?
<!--
If possible, provide a recipe for reproducing the bug.
-->
### What did you expect to see?
<!--
- A description of the results you expected to get from the recipe above.
-->
### What did you see instead?
<!--
- A description of what actually happens when you perform these steps.
- Please include any error output if relevant.
-->
### Enso Version
<!--
- Please include the version of Enso IDE you are using here.
-->

View File

@ -1,30 +1,33 @@
---
name: Epic
about: Create a new epic for Enso IDE development.
title: ''
labels: ''
assignees: ''
title: ""
labels: ""
assignees: ""
---
### Summary
<!--
- This section should summarise the work we want to accomplish during the epic.
-->
### Value
<!--
- A description of the value this epic brings to users.
- The motivation behind this epic.
-->
### Specification
<!--
- The high-level requirements of the epic.
- Any performance requirements for the epic.
-->
### Acceptance Criteria & Test Cases
<!--
- The high-level acceptance criteria for the epic.
- The test plan for the epic.

View File

@ -1,10 +1,9 @@
---
name: Feature Request
about: Request a new feature in Enso IDE.
title: ''
labels: 'Type: Enhancement'
assignees: ''
title: ""
labels: "Type: Enhancement"
assignees: ""
---
<!--
@ -13,11 +12,13 @@ has been implemented.
-->
### General Summary
<!--
- Describe the feature you are requesting.
-->
### Motivation
<!--
- A description of the motivation for adding this feature to Enso IDE.
- Ideally this would include use-cases that support the feature.

View File

@ -1,30 +1,33 @@
---
name: Task
about: Create a new development task for Enso IDE.
title: ''
labels: ''
assignees: ''
title: ""
labels: ""
assignees: ""
---
### Summary
<!--
- A summary of the task.
-->
### Value
<!--
- This section should describe the value of this task.
- This value can be for users, to the team, etc.
-->
### Specification
<!--
- Detailed requirements for the feature.
- The performance requirements for the feature.
-->
### Acceptance Criteria & Test Cases
<!--
- Any criteria that must be satisfied for the task to be accepted.
- The test plan for the feature, related to the acceptance criteria.

View File

@ -1,24 +1,31 @@
### Pull Request Description
<!--
- Please describe the nature of your PR here, as well as the motivation for it.
- If it fixes an open issue, please mention that issue number here.
-->
### Important Notes
<!--
- Mention important elements of the design.
- Mention any notable changes to APIs.
-->
### Checklist
Please include the following checklist in your PR:
- [ ] The `CHANGELOG.md` was updated with the changes introduced in this PR.
- [ ] The documentation has been updated if necessary.
- [ ] All code conforms to the [Rust](https://github.com/enso-org/enso/blob/develop/docs/style-guide/rust.md) style guide.
- [ ] All code conforms to the
[Rust](https://github.com/enso-org/enso/blob/develop/docs/style-guide/rust.md)
style guide.
- [ ] All code has automatic tests where possible.
- [ ] All code has been profiled where possible.
- [ ] All code has been manually tested in the IDE.
- [ ] All code has been manually tested in the "debug/interface" scene.
- [ ] All code has been manually tested by the PR owner against our [test scenarios](https://airtable.com/shr7KPRypRpanF7TO).
- [ ] All code has been manually tested by at least one reviewer against our [test scenarios](https://airtable.com/shr7KPRypRpanF7TO).
- [ ] All code has been manually tested by the PR owner against our
[test scenarios](https://airtable.com/shr7KPRypRpanF7TO).
- [ ] All code has been manually tested by at least one reviewer against our
[test scenarios](https://airtable.com/shr7KPRypRpanF7TO).

View File

@ -5,7 +5,7 @@ on:
branches:
- develop
paths:
- 'docs/**'
- "docs/**"
jobs:
checkout:
@ -13,8 +13,8 @@ jobs:
steps:
- uses: actions/checkout@v2
with:
repository: 'enso-org/enso-org.github.io'
ref: 'sources'
repository: "enso-org/enso-org.github.io"
ref: "sources"
token: ${{ secrets.ENSO_PAT }}
- name: set identity email
run: git config --global user.email "actions@github.com"

View File

@ -1,2 +0,0 @@
**/lib/**/*.js
**/target/*

View File

@ -4,11 +4,13 @@ const exec = require('child_process').exec
function download(url) {
return new Promise((resolve, reject) => {
https.get(url,(res) => {
let data = ""
res.on("data", (chunk) => data += chunk)
res.on("end", () => resolve(data))
}).on("error", (error) => reject(error))
https
.get(url, res => {
let data = ''
res.on('data', chunk => (data += chunk))
res.on('end', () => resolve(data))
})
.on('error', error => reject(error))
})
}
@ -37,7 +39,7 @@ function run(cmd,args) {
return new Promise((resolve, reject) => {
console.log(`Calling '${cmd} ${args.join(' ')}'`)
let proc = spawn(cmd, args, { stdio: 'inherit', shell: true })
proc.on('exit', (code) => {
proc.on('exit', code => {
if (code) process.exit(code)
resolve(out)
})
@ -49,19 +51,25 @@ function run_read(cmd,args) {
return new Promise((resolve, reject) => {
let proc = spawn(cmd, args, { shell: true })
proc.stderr.pipe(process.stderr)
proc.stdout.on('data', (data) => { out += data })
proc.on('exit', (code) => {
if (code) process.exit(code);
proc.stdout.on('data', data => {
out += data
})
proc.on('exit', code => {
if (code) process.exit(code)
resolve(out)
})
})
}
async function check_version(name, required, cfg) {
if (!cfg) { cfg = {} }
if (!cfg) {
cfg = {}
}
let version = await run_read(name, ['--version'])
version = version.trim()
if (cfg.preprocess) { version = cfg.preprocess(version) }
if (cfg.preprocess) {
version = cfg.preprocess(version)
}
if (cfg.silent !== true) {
console.log(`Checking if '${name}' version is '${required}'.`)
}
@ -96,12 +104,21 @@ async function get_node_lts_version() {
}
}
if (!newest) {
throw "Cannot fetch the info about node LTS version."
throw 'Cannot fetch the info about node LTS version.'
}
let node = newest.version
let npm = newest.npm
return [node, npm]
}
module.exports = {section,run,run_read,check_version,get_npm_info,get_npm_lts_version_of,with_cwd,
get_node_dist_index,get_node_lts_version}
module.exports = {
section,
run,
run_read,
check_version,
get_npm_info,
get_npm_lts_version_of,
with_cwd,
get_node_dist_index,
get_node_lts_version,
}

View File

@ -1,8 +1,6 @@
const path = require('path')
const os = require('os')
// =============
// === Paths ===
// =============
@ -59,7 +57,7 @@ function get_project_manager_extension() {
}
paths.get_project_manager_path = function (root) {
let base_path = path.join(root, 'enso', 'bin',)
let base_path = path.join(root, 'enso', 'bin')
const extension = get_project_manager_extension()
return path.join(base_path, 'project-manager') + extension
}

View File

@ -7,8 +7,6 @@ const paths = require('./paths')
const semver = require('semver')
const config = require('../config')
// =================
// === Constants ===
// =================
@ -17,8 +15,6 @@ const CHANGELOG_FILE_NAME = 'CHANGELOG.md'
const CHANGELOG_FILE = path.join(paths.root, CHANGELOG_FILE_NAME)
const ENGINE_VERSION = config.engineVersion
// ===============
// === Version ===
// ===============
@ -26,7 +22,7 @@ const ENGINE_VERSION = config.engineVersion
class NextReleaseVersion {
/// Version used for config files when building the package with "next version" in changelog.
toString() {
return "0.0.0"
return '0.0.0'
}
isPrerelease() {
@ -46,19 +42,39 @@ class Version {
}
lt(that) {
if (this.major < that.major) { return true }
if (this.minor < that.minor) { return true }
if (this.patch < that.patch) { return true }
if (this.tag === 'alpha' && that.tag === 'beta') { return true }
if (this.tag === 'alpha' && that.tag === 'rc') { return true }
if (this.tag === 'beta' && that.tag === 'rc') { return true }
if (this.tagVersion < that.tagVersion) { return true }
if (this.rcTagVersion < that.rcTagVersion) { return true }
if (this.major < that.major) {
return true
}
if (this.minor < that.minor) {
return true
}
if (this.patch < that.patch) {
return true
}
if (this.tag === 'alpha' && that.tag === 'beta') {
return true
}
if (this.tag === 'alpha' && that.tag === 'rc') {
return true
}
if (this.tag === 'beta' && that.tag === 'rc') {
return true
}
if (this.tagVersion < that.tagVersion) {
return true
}
if (this.rcTagVersion < that.rcTagVersion) {
return true
}
return false
}
isPrerelease() {
if (this.tag) { return true } else { return false }
if (this.tag) {
return true
} else {
return false
}
}
toString() {
@ -73,8 +89,6 @@ class Version {
}
}
// ======================
// === ChangelogEntry ===
// ======================
@ -94,14 +108,14 @@ class ChangelogEntry {
assert_is_unstable() {
this.assert_is_newest_version_defined()
if (!this.isPrerelease()) {
throw "Assertion failed. The version is stable."
throw 'Assertion failed. The version is stable.'
}
}
assert_is_stable() {
this.assert_is_newest_version_defined()
if (this.isPrerelease()) {
throw "Assertion failed. The version is unstable."
throw 'Assertion failed. The version is unstable.'
}
}
@ -110,8 +124,6 @@ class ChangelogEntry {
}
}
// =================
// === Changelog ===
// =================
@ -131,9 +143,9 @@ class Changelog {
}
function changelogSections() {
let text = '\n' + fss.readFileSync(CHANGELOG_FILE,"utf8")
let text = '\n' + fss.readFileSync(CHANGELOG_FILE, 'utf8')
let chunks = text.split(/\r?\n#(?!#)/)
return chunks.filter((s) => s != '')
return chunks.filter(s => s != '')
}
function changelogEntries() {
@ -145,16 +157,25 @@ function changelogEntries() {
let header = section.substring(0, splitPoint)
let body = section.substring(splitPoint).trim()
if (firstSection && header.startsWith(' Next Release')) {
let version = new NextReleaseVersion
let version = new NextReleaseVersion()
entries.push(new ChangelogEntry(version, body))
} else {
let headerReg = /^ Enso (?<major>[0-9]+)\.(?<minor>[0-9]+)\.(?<patch>[0-9]+)(-(?<tag>alpha|beta|rc)\.(?<tagVersion>[0-9]+))?(.(?<rcTag>rc)\.(?<rcTagVersion>[0-9]+))? \((?<year>[0-9][0-9][0-9][0-9])-(?<month>[0-9][0-9])-(?<day>[0-9][0-9])\)/
let headerReg =
/^ Enso (?<major>[0-9]+)\.(?<minor>[0-9]+)\.(?<patch>[0-9]+)(-(?<tag>alpha|beta|rc)\.(?<tagVersion>[0-9]+))?(.(?<rcTag>rc)\.(?<rcTagVersion>[0-9]+))? \((?<year>[0-9][0-9][0-9][0-9])-(?<month>[0-9][0-9])-(?<day>[0-9][0-9])\)/
let match = header.match(headerReg)
if (!match) {
throw `Improper changelog entry header: '${header}'. See the 'CHANGELOG_TEMPLATE.md' for details.`
}
let grps = match.groups
let version = new Version(grps.major,grps.minor,grps.patch,grps.tag,grps.tagVersion,grps.rcTag,grps.rcTagVersion)
let version = new Version(
grps.major,
grps.minor,
grps.patch,
grps.tag,
grps.tagVersion,
grps.rcTag,
grps.rcTagVersion
)
entries.push(new ChangelogEntry(version, body))
}
firstSection = false
@ -179,15 +200,13 @@ function changelogEntries() {
}
function changelog() {
return new Changelog
return new Changelog()
}
function currentVersion() {
return changelog().currentVersion()
}
// ===============
// === Exports ===
// ===============

View File

@ -9,7 +9,7 @@ const ncp = require('ncp').ncp
const os = require('os')
const path = require('path')
const paths = require('./paths')
const prettier = require("prettier")
const prettier = require('prettier')
const release = require('./release')
const stream = require('stream')
const workflow = require('./workflow')
@ -18,17 +18,15 @@ const zlib = require('zlib')
const { promisify } = require('util')
const pipe = promisify(stream.pipeline)
// ==============
// === Errors ===
// ==============
process.on('unhandledRejection', error => { throw(error) })
process.on('unhandledRejection', error => {
throw error
})
process.chdir(paths.root)
// ========================
// === Global Variables ===
// ========================
@ -41,8 +39,6 @@ let cargoArgs = undefined
// command line args get parsed.
let targetArgs = undefined
// =============
// === Utils ===
// =============
@ -57,8 +53,10 @@ async function gzip(input, output) {
/// Copy files and directories.
async function copy(src, tgt) {
return new Promise((resolve, reject) => {
ncp(src,tgt,(err) => {
if (err) { reject(`${err}`) }
ncp(src, tgt, err => {
if (err) {
reject(`${err}`)
}
resolve()
})
})
@ -74,7 +72,6 @@ async function run(command,args) {
await cmd.run(command, args)
}
/// Defines a new command argument builder.
function command(docs) {
return { docs }
@ -103,8 +100,6 @@ function run_project_manager() {
})
}
// ================
// === Commands ===
// ================
@ -112,7 +107,6 @@ function run_project_manager() {
const DEFAULT_CRATE = 'ide'
let commands = {}
// === Clean ===
commands.clean = command(`Clean all build artifacts`)
@ -130,7 +124,6 @@ commands.clean.rust = async function() {
await run_cargo('cargo', ['clean'])
}
// === Check ===
commands.check = command(`Fast check if project builds (only Rust target)`)
@ -138,15 +131,14 @@ commands.check.rust = async function() {
await run_cargo('cargo', ['check'])
}
// === Build ===
commands.build = command(`Build the sources in release mode`)
commands.build.options = {
'crate': {
crate: {
describe: 'Target crate to build',
type: 'string',
}
},
}
commands.build.js = async function () {
await installJsDeps()
@ -158,8 +150,19 @@ commands.build.rust = async function(argv) {
let crate = argv.crate || DEFAULT_CRATE
let crate_sfx = crate ? ` '${crate}'` : ``
console.log(`Building WASM target${crate_sfx}.`)
let args = ['build','--target','web','--out-dir',paths.dist.wasm.root,'--out-name','ide',crate]
if (argv.dev) { args.push('--dev') }
let args = [
'build',
'--target',
'web',
'--out-dir',
paths.dist.wasm.root,
'--out-name',
'ide',
crate,
]
if (argv.dev) {
args.push('--dev')
}
await run_cargo('wasm-pack', args)
await patch_file(paths.dist.wasm.glue, js_workaround_patcher)
await fs.rename(paths.dist.wasm.mainRaw, paths.dist.wasm.main)
@ -173,10 +176,10 @@ commands.build.rust = async function(argv) {
console.log('Checking the resulting WASM size.')
let stats = fss.statSync(paths.dist.wasm.mainOptGz)
let limit = 4.60
let size = Math.round(100 * stats.size / 1024 / 1024) / 100
let limit = 4.6
let size = Math.round((100 * stats.size) / 1024 / 1024) / 100
if (size > limit) {
throw(`Output file size exceeds the limit (${size}MB > ${limit}MB).`)
throw `Output file size exceeds the limit (${size}MB > ${limit}MB).`
}
}
}
@ -186,7 +189,7 @@ function js_workaround_patcher(code) {
code = code.replace(/if \(\(typeof URL.*}\);/gs, 'return imports')
code = code.replace(/if \(typeof module.*let result/gs, 'let result')
code = code.replace(/export default init;/gs, 'export default init')
code += '\nexport function after_load\(w,m\) { wasm = w; init.__wbindgen_wasm_module = m;}'
code += '\nexport function after_load(w,m) { wasm = w; init.__wbindgen_wasm_module = m;}'
return code
}
@ -196,7 +199,6 @@ async function patch_file(path,patcher) {
await fs.writeFile(path, patched_code)
}
// === Start ===
commands.start = command(`Build and start desktop client`)
@ -211,14 +213,17 @@ commands.start.js = async function (argv) {
// The backend path is being prepended here, as appending would be incorrect.
// That is because `targetArgs` might include `-- …` and appended args could
// end up being passed to the spawned backend process.
const args = ['--backend-path', paths.get_project_manager_path(paths.dist.bin)].concat(targetArgs)
if (argv.dev) { args.push('--dev') }
const args = ['--backend-path', paths.get_project_manager_path(paths.dist.bin)].concat(
targetArgs
)
if (argv.dev) {
args.push('--dev')
}
await cmd.with_cwd(paths.js.root, async () => {
await run('npm', ['run', 'start', '--'].concat(args))
})
}
// === Test ===
commands.test = command(`Run test suites`)
@ -230,12 +235,19 @@ commands.test.rust = async function(argv) {
if (argv.wasm) {
console.log(`Running Rust WASM test suite.`)
let args = ['run','--manifest-path=test/Cargo.toml','--bin','test_all','--','--headless','--chrome']
let args = [
'run',
'--manifest-path=test/Cargo.toml',
'--bin',
'test_all',
'--',
'--headless',
'--chrome',
]
await run_cargo('cargo', args)
}
}
// === Lint ===
commands.lint = command(`Lint the codebase`)
@ -244,23 +256,21 @@ commands.lint.rust = async function() {
await run_cargo('cargo', ['fmt', '--', '--check'])
}
// === TomlFmt ===
commands['toml-fmt'] = command(`Lint the codebase`)
commands['toml-fmt'].rust = async function () {
console.log("Looking for all TOML files.")
let files = glob.sync(paths.rust.root + "/**/*.toml", {cwd:paths.root});
console.log('Looking for all TOML files.')
let files = glob.sync(paths.rust.root + '/**/*.toml', { cwd: paths.root })
console.log(`Found ${files.length} entries. Running auto-formatter.`)
for (let file of files) {
console.log(` Formatting '${file}'.`)
let text = fss.readFileSync(file, "utf8")
let text = fss.readFileSync(file, 'utf8')
let out = prettier.format(text, { parser: 'toml' })
fss.writeFileSync(file, out)
}
}
// === Watch ===
commands.watch = command(`Start a file-watch utility and run interactive mode`)
@ -279,7 +289,7 @@ commands.watch.common = async function(argv) {
// Run build processes.
await cmd.with_cwd(paths.rust.root, async () => {
return commands.build.rust(argv);
return commands.build.rust(argv)
})
await cmd.with_cwd(paths.js.root, async () => {
// Among other things, this will call the build script of the project-manager package. But
@ -305,14 +315,13 @@ commands.watch.common = async function(argv) {
return cmd.run('cargo', args)
})
const js_process = cmd.with_cwd(paths.js.root, async () => {
return run('npm',['run','watch']);
return run('npm', ['run', 'watch'])
})
await rust_process
await js_process
}
// === Dist ===
commands.dist = command(`Build the sources and create distribution packages`)
@ -327,7 +336,6 @@ commands.dist.js = async function() {
})
}
// === CI Gen ===
/// The command is used by CI to generate the file `CURRENT_RELEASE_CHANGELOG.json`, which contains
@ -339,7 +347,7 @@ commands['ci-gen'].rust = async function(argv) {
let body = entry.body
let version = entry.version.toString()
let prerelease = entry.isPrerelease()
let obj = {version,body,prerelease};
let obj = { version, body, prerelease }
let json = JSON.stringify(obj)
fss.writeFileSync(path.join(paths.root, 'CURRENT_RELEASE_CHANGELOG.json'), json)
}
@ -356,8 +364,6 @@ commands['assert-version-stable'].rust = async function(argv) {
let entry = release.changelog().newestEntry().assert_is_stable()
}
// ===========================
// === Command Line Parser ===
// ===========================
@ -370,7 +376,7 @@ For example, 'run start -- --dev -- --debug-scene shapes' will pass '--dev' to c
and '--debug-scene shapes' to the output binary.`
let optParser = yargs
.scriptName("")
.scriptName('')
.usage(usage)
.help()
.parserConfiguration({ 'populate--': true })
@ -379,22 +385,22 @@ let optParser = yargs
optParser.options('rust', {
describe: 'Run the Rust target',
type: 'bool',
default : true
default: true,
})
optParser.options('js', {
describe: 'Run the JavaScript target',
type: 'bool',
default : true
default: true,
})
optParser.options('release', {
describe : "Enable all optimizations",
describe: 'Enable all optimizations',
type: 'bool',
})
optParser.options('dev', {
describe : "Optimize for fast builds",
describe: 'Optimize for fast builds',
type: 'bool',
})
@ -415,7 +421,7 @@ let commandList = Object.keys(commands)
commandList.sort()
for (let command of commandList) {
let config = commands[command]
optParser.command(command,config.docs,(args) => {
optParser.command(command, config.docs, args => {
for (let option in config.options) {
args.options(option, config.options[option])
}
@ -425,18 +431,16 @@ for (let command of commandList) {
args.options('native', {
describe: 'Run native tests',
type: 'bool',
default : true
default: true,
})
args.options('wasm', {
describe: 'Run WASM tests',
type: 'bool',
default : true
default: true,
})
})
}
// ======================
// === Package Config ===
// ======================
@ -445,24 +449,24 @@ function defaultConfig() {
return {
version: `${release.currentVersion()}`,
author: {
name: "Enso Team",
email: "contact@enso.org"
name: 'Enso Team',
email: 'contact@enso.org',
},
homepage: "https://github.com/enso-org/ide",
homepage: 'https://github.com/enso-org/ide',
repository: {
type: "git",
url: "git@github.com:enso-org/ide.git"
type: 'git',
url: 'git@github.com:enso-org/ide.git',
},
bugs: {
url: "https://github.com/enso-org/ide/issues"
url: 'https://github.com/enso-org/ide/issues',
},
}
}
async function processPackageConfigs() {
let files = []
files = files.concat(glob.sync(paths.js.root + "/package.js", {cwd:paths.root}))
files = files.concat(glob.sync(paths.js.root + "/lib/*/package.js", {cwd:paths.root}))
files = files.concat(glob.sync(paths.js.root + '/package.js', { cwd: paths.root }))
files = files.concat(glob.sync(paths.js.root + '/lib/*/package.js', { cwd: paths.root }))
for (file of files) {
let dirPath = path.dirname(file)
let outPath = path.join(dirPath, 'package.json')
@ -471,14 +475,14 @@ async function processPackageConfigs() {
let fn = new Function('require', 'paths', modSrc)
let mod = fn(require, paths)
let config = mod.config
if (!config) { throw(`Package config '${file}' do not export 'module.config'.`) }
if (!config) {
throw `Package config '${file}' do not export 'module.config'.`
}
config = Object.assign(defaultConfig(), config)
fs.writeFile(outPath, JSON.stringify(config, undefined, 4))
}
}
// ============
// === Main ===
// ============
@ -493,11 +497,7 @@ async function updateBuildVersion (argv) {
config = JSON.parse(configFile)
}
let commitHashCmd = await cmd.run_read('git', [
'rev-parse',
'--short',
'HEAD'
])
let commitHashCmd = await cmd.run_read('git', ['rev-parse', '--short', 'HEAD'])
let commitHash = commitHashCmd.trim()
if (config.buildVersion !== commitHash || config.target !== target) {
@ -506,7 +506,6 @@ async function updateBuildVersion (argv) {
await fs.mkdir(paths.dist.root, { recursive: true })
await fs.writeFile(configPath, JSON.stringify(config, undefined, 2))
}
}
async function installJsDeps() {
@ -556,12 +555,13 @@ async function runCommand(command, argv) {
console.error(`Invalid command '${command}'.`)
return
}
if(cargoArgs === undefined) { cargoArgs = [] }
if (cargoArgs === undefined) {
cargoArgs = []
}
let index = cargoArgs.indexOf('--')
if (index == -1) {
targetArgs = []
}
else {
} else {
targetArgs = cargoArgs.slice(index + 1)
cargoArgs = cargoArgs.slice(0, index)
}
@ -575,14 +575,26 @@ async function runCommand(command, argv) {
let jsCmd = () => cmd.with_cwd(paths.js.root, async () => await config.js(argv))
if (config.parallel) {
let promises = []
if (do_common ) { promises.push(commonCmd()) }
if (do_rust) { promises.push(rustCmd()) }
if (do_js) { promises.push(jsCmd()) }
if (do_common) {
promises.push(commonCmd())
}
if (do_rust) {
promises.push(rustCmd())
}
if (do_js) {
promises.push(jsCmd())
}
await Promise.all(promises)
} else {
if (do_common) { await commonCmd() }
if (do_rust) { await rustCmd() }
if (do_js) { await jsCmd() }
if (do_common) {
await commonCmd()
}
if (do_rust) {
await rustCmd()
}
if (do_js) {
await jsCmd()
}
}
}
cmd.section(command)

View File

@ -129,8 +129,8 @@ let installClippy = {
}
let installFmt = {
name: "Install Clippy",
run: "rustup component add rustfmt"
name: 'Install Clippy',
run: 'rustup component add rustfmt',
}
// Install fixed version to avoid upgrading to a breaking version.
@ -424,8 +424,7 @@ let assertReleaseDoNotExists = [
assertNoSquashCommitForRelease = {
name: `Fail if squash commit to the 'unstable' or the 'stable' branch.`,
run:
'if [[ "${{ github.base_ref }}" == "unstable" || "${{ github.base_ref }}" == "stable" ]]; then exit 1; fi',
run: 'if [[ "${{ github.base_ref }}" == "unstable" || "${{ github.base_ref }}" == "stable" ]]; then exit 1; fi',
}
let assertions = list(

View File

@ -1,72 +1,96 @@
# Next Release
This update contains major performance improvements and exposes new privacy user settings. We will
work towards stabilizing it in the next weeks in order to make these updates be shipped in a stable
release before the end of the year.
This update contains major performance improvements and exposes new privacy user
settings. We will work towards stabilizing it in the next weeks in order to make
these updates be shipped in a stable release before the end of the year.
<br/>![New Features](/docs/assets/tags/new_features.svg)
#### Visual Environment
- [You can now launch missiles directly from the GUI][79270]. It was technically possible since
version 3.0.0-alpha.7, but it was never exposed as a button.
- [The graph editor stops shaking and running away when you are pasting JavaScript code][79271].
- [You can now launch missiles directly from the GUI][79270]. It was technically
possible since version 3.0.0-alpha.7, but it was never exposed as a button.
- [The graph editor stops shaking and running away when you are pasting
JavaScript code][79271].
#### Runtime
- [The JiT compiler got new optimizations and produces code up to 10x faster than C++][79272].
- [You do not need to keep your computer in -20°C to prevent the engine from crashing anymore][79273].
- [The JiT compiler got new optimizations and produces code up to 10x faster
than C++][79272].
- [You do not need to keep your computer in -20°C to prevent the engine from
crashing anymore][79273].
#### Libraries
- [The new JSON library allows you to parse 2Gb files in 50ms][79274].
- [The Regexp library exposes now methods to test the expressions directly on humans][79275].
- [The new JSON library allows you to parse 2Gb files in 50ms][79274].
- [The Regexp library exposes now methods to test the expressions directly on
humans][79275].
<br/>![Bug Fixes](/docs/assets/tags/bug_fixes.svg)
#### Visual Environment
- [You can now launch missiles directly from the GUI][79270]. It was technically possible since
version 3.0.0-alpha.7, but it was never exposed as a button.
- [The graph editor stops shaking and running away when you are pasting JavaScript code][79271].
- [You can now launch missiles directly from the GUI][79270]. It was technically
possible since version 3.0.0-alpha.7, but it was never exposed as a button.
- [The graph editor stops shaking and running away when you are pasting
JavaScript code][79271].
#### Runtime
- [The JiT compiler got new optimizations and produces code up to 10x faster than C++][79272].
- [You do not need to keep your computer in -20°C to prevent the engine from crashing anymore][79273].
- [The JiT compiler got new optimizations and produces code up to 10x faster
than C++][79272].
- [You do not need to keep your computer in -20°C to prevent the engine from
crashing anymore][79273].
#### Libraries
- [The new JSON library allows you to parse 2Gb files in 50ms][79274].
- [The Regexp library exposes now methods to test the expressions directly on humans][79275].
- [The new JSON library allows you to parse 2Gb files in 50ms][79274].
- [The Regexp library exposes now methods to test the expressions directly on
humans][79275].
<br/>![New Learning Resources](/docs/assets/tags/new_learning_resources.svg)
#### Visual Environment
- [You can now launch missiles directly from the GUI][79270]. It was technically possible since
version 3.0.0-alpha.7, but it was never exposed as a button.
- [The graph editor stops shaking and running away when you are pasting JavaScript code][79271].
- [You can now launch missiles directly from the GUI][79270]. It was technically
possible since version 3.0.0-alpha.7, but it was never exposed as a button.
- [The graph editor stops shaking and running away when you are pasting
JavaScript code][79271].
#### Runtime
- [The JiT compiler got new optimizations and produces code up to 10x faster than C++][79272].
- [You do not need to keep your computer in -20°C to prevent the engine from crashing anymore][79273].
- [The JiT compiler got new optimizations and produces code up to 10x faster
than C++][79272].
- [You do not need to keep your computer in -20°C to prevent the engine from
crashing anymore][79273].
#### Libraries
- [The new JSON library allows you to parse 2Gb files in 50ms][79274].
- [The Regexp library exposes now methods to test the expressions directly on humans][79275].
- [The new JSON library allows you to parse 2Gb files in 50ms][79274].
- [The Regexp library exposes now methods to test the expressions directly on
humans][79275].
<br/>![Release Notes](/docs/assets/tags/release_notes.svg)
#### Visual Environment
- [You can now launch missiles directly from the GUI][79270]. It was technically possible since
version 3.0.0-alpha.7, but it was never exposed as a button.
- [The graph editor stops shaking and running away when you are pasting JavaScript code][79271].
- [You can now launch missiles directly from the GUI][79270]. It was technically
possible since version 3.0.0-alpha.7, but it was never exposed as a button.
- [The graph editor stops shaking and running away when you are pasting
JavaScript code][79271].
#### Runtime
- [The JiT compiler got new optimizations and produces code up to 10x faster than C++][79272].
- [You do not need to keep your computer in -20°C to prevent the engine from crashing anymore][79273].
- [The JiT compiler got new optimizations and produces code up to 10x faster
than C++][79272].
- [You do not need to keep your computer in -20°C to prevent the engine from
crashing anymore][79273].
#### Libraries
- [The new JSON library allows you to parse 2Gb files in 50ms][79274].
- [The Regexp library exposes now methods to test the expressions directly on humans][79275].
- [The new JSON library allows you to parse 2Gb files in 50ms][79274].
- [The Regexp library exposes now methods to test the expressions directly on
humans][79275].
[79270]: http://github.com/ticket
[79271]: http://github.com/ticket
@ -74,79 +98,102 @@ release before the end of the year.
[79273]: http://github.com/ticket
[79274]: http://github.com/ticket
[79275]: http://github.com/ticket
<br/>
# Enso 47.0.0-alpha.8 (2049-01-22)
This update contains major performance improvements and exposes new privacy user settings. We will
work towards stabilizing it in the next weeks in order to make these updates be shipped in a stable
release before the end of the year.
This update contains major performance improvements and exposes new privacy user
settings. We will work towards stabilizing it in the next weeks in order to make
these updates be shipped in a stable release before the end of the year.
<br/>![New Features](/docs/assets/tags/new_features.svg)
#### Visual Environment
- [You can now launch missiles directly from the GUI][79270]. It was technically possible since
version 3.0.0-alpha.7, but it was never exposed as a button.
- [The graph editor stops shaking and running away when you are pasting JavaScript code][79271].
- [You can now launch missiles directly from the GUI][79270]. It was technically
possible since version 3.0.0-alpha.7, but it was never exposed as a button.
- [The graph editor stops shaking and running away when you are pasting
JavaScript code][79271].
#### Runtime
- [The JiT compiler got new optimizations and produces code up to 10x faster than C++][79272].
- [You do not need to keep your computer in -20°C to prevent the engine from crashing anymore][79273].
- [The JiT compiler got new optimizations and produces code up to 10x faster
than C++][79272].
- [You do not need to keep your computer in -20°C to prevent the engine from
crashing anymore][79273].
#### Libraries
- [The new JSON library allows you to parse 2Gb files in 50ms][79274].
- [The Regexp library exposes now methods to test the expressions directly on humans][79275].
- [The new JSON library allows you to parse 2Gb files in 50ms][79274].
- [The Regexp library exposes now methods to test the expressions directly on
humans][79275].
<br/>![Bug Fixes](/docs/assets/tags/bug_fixes.svg)
#### Visual Environment
- [You can now launch missiles directly from the GUI][79270]. It was technically possible since
version 3.0.0-alpha.7, but it was never exposed as a button.
- [The graph editor stops shaking and running away when you are pasting JavaScript code][79271].
- [You can now launch missiles directly from the GUI][79270]. It was technically
possible since version 3.0.0-alpha.7, but it was never exposed as a button.
- [The graph editor stops shaking and running away when you are pasting
JavaScript code][79271].
#### Runtime
- [The JiT compiler got new optimizations and produces code up to 10x faster than C++][79272].
- [You do not need to keep your computer in -20°C to prevent the engine from crashing anymore][79273].
- [The JiT compiler got new optimizations and produces code up to 10x faster
than C++][79272].
- [You do not need to keep your computer in -20°C to prevent the engine from
crashing anymore][79273].
#### Libraries
- [The new JSON library allows you to parse 2Gb files in 50ms][79274].
- [The Regexp library exposes now methods to test the expressions directly on humans][79275].
- [The new JSON library allows you to parse 2Gb files in 50ms][79274].
- [The Regexp library exposes now methods to test the expressions directly on
humans][79275].
<br/>![New Learning Resources](/docs/assets/tags/new_learning_resources.svg)
#### Visual Environment
- [You can now launch missiles directly from the GUI][79270]. It was technically possible since
version 3.0.0-alpha.7, but it was never exposed as a button.
- [The graph editor stops shaking and running away when you are pasting JavaScript code][79271].
- [You can now launch missiles directly from the GUI][79270]. It was technically
possible since version 3.0.0-alpha.7, but it was never exposed as a button.
- [The graph editor stops shaking and running away when you are pasting
JavaScript code][79271].
#### Runtime
- [The JiT compiler got new optimizations and produces code up to 10x faster than C++][79272].
- [You do not need to keep your computer in -20°C to prevent the engine from crashing anymore][79273].
- [The JiT compiler got new optimizations and produces code up to 10x faster
than C++][79272].
- [You do not need to keep your computer in -20°C to prevent the engine from
crashing anymore][79273].
#### Libraries
- [The new JSON library allows you to parse 2Gb files in 50ms][79274].
- [The Regexp library exposes now methods to test the expressions directly on humans][79275].
- [The new JSON library allows you to parse 2Gb files in 50ms][79274].
- [The Regexp library exposes now methods to test the expressions directly on
humans][79275].
<br/>![Release Notes](/docs/assets/tags/release_notes.svg)
#### Visual Environment
- [You can now launch missiles directly from the GUI][79270]. It was technically possible since
version 3.0.0-alpha.7, but it was never exposed as a button.
- [The graph editor stops shaking and running away when you are pasting JavaScript code][79271].
- [You can now launch missiles directly from the GUI][79270]. It was technically
possible since version 3.0.0-alpha.7, but it was never exposed as a button.
- [The graph editor stops shaking and running away when you are pasting
JavaScript code][79271].
#### Runtime
- [The JiT compiler got new optimizations and produces code up to 10x faster than C++][79272].
- [You do not need to keep your computer in -20°C to prevent the engine from crashing anymore][79273].
- [The JiT compiler got new optimizations and produces code up to 10x faster
than C++][79272].
- [You do not need to keep your computer in -20°C to prevent the engine from
crashing anymore][79273].
#### Libraries
- [The new JSON library allows you to parse 2Gb files in 50ms][79274].
- [The Regexp library exposes now methods to test the expressions directly on humans][79275].
- [The new JSON library allows you to parse 2Gb files in 50ms][79274].
- [The Regexp library exposes now methods to test the expressions directly on
humans][79275].
[79270]: http://github.com/ticket
[79271]: http://github.com/ticket
@ -154,9 +201,9 @@ release before the end of the year.
[79273]: http://github.com/ticket
[79274]: http://github.com/ticket
[79275]: http://github.com/ticket
<br/>
# Enso 47.0.0-alpha.7 (2049-01-07)
...

View File

@ -7,7 +7,7 @@ tags: [doc-index]
# Enso IDE documentation
* [**Contributing guidelines**](./contributing/README.md) - helpful
instructions for anyone who wants to contribute.
* [**Product specification**](./product/README.md) - a specification from
the user perspective.
- [**Contributing guidelines**](./contributing/README.md) - helpful instructions
for anyone who wants to contribute.
- [**Product specification**](./product/README.md) - a specification from the
user perspective.

View File

@ -7,8 +7,9 @@ tags: [contributing]
# Enso IDE Contributing Documentation
This directory contains helpful resources for anyone who wants to start Enso IDE development. The
main guideline is available [here](../CONTRIBUTING.md).
This directory contains helpful resources for anyone who wants to start Enso IDE
development. The main guideline is available [here](../CONTRIBUTING.md).
* [**Enso Team Process**](./process.md) - the development cycle in the core Enso IDE team.
* [**Style Guide**](./style-guide.md) - Our coding standards.
- [**Enso Team Process**](./process.md) - the development cycle in the core Enso
IDE team.
- [**Style Guide**](./style-guide.md) - Our coding standards.

View File

@ -7,16 +7,21 @@ tags: [contributing]
# Enso IDE Team Process
This document specify our core team workflow, described as a lifecycle of a task:
This document specify our core team workflow, described as a lifecycle of a
task:
* A newly created task should be appropriately described, but not estimated yet - it will be during
Backlog Refinement meeting. The task is put in "New Tasks" column.
* At the beginning of the sprint team leads put to the "To Refine" column all tasks which will be
refined during the next Backlog refinement.
* Each team member should read the descriptions of tasks in "To Refine" column and ask questions
and raise all concerns. All the conversation should be recorded in the issue's comments.
* During Backlog Refinement we confirm that the task description is clear and estimate it. The
estimate is expressed in work days of one person, and should include the review process. The task
is then moved to the "Backlog" column. If it turns out that there is no agreement about the task's
scope and estimation, it may be postponed to the next Backlog Refinement.
* During Planning meeting the team decides which tasks are took into next sprint and assign them.
- A newly created task should be appropriately described, but not estimated
yet - it will be during Backlog Refinement meeting. The task is put in "New
Tasks" column.
- At the beginning of the sprint team leads put to the "To Refine" column all
tasks which will be refined during the next Backlog refinement.
- Each team member should read the descriptions of tasks in "To Refine" column
and ask questions and raise all concerns. All the conversation should be
recorded in the issue's comments.
- During Backlog Refinement we confirm that the task description is clear and
estimate it. The estimate is expressed in work days of one person, and should
include the review process. The task is then moved to the "Backlog" column. If
it turns out that there is no agreement about the task's scope and estimation,
it may be postponed to the next Backlog Refinement.
- During Planning meeting the team decides which tasks are took into next sprint
and assign them.

View File

@ -1,9 +1,9 @@
# Repository Structure Overview
* `build` - Helper JS scripts used by `run` script in the main directory.
* `docs` - Documentation.
* `src/js` - The JS part of IDE application.
* `src/rust` - All Rust crates.
- `build` - Helper JS scripts used by `run` script in the main directory.
- `docs` - Documentation.
- `src/js` - The JS part of IDE application.
- `src/rust` - All Rust crates.
## Crates
@ -11,15 +11,15 @@ The crates structure is currently in process of refactoring, and there are still
places where code does not fit the crate it is placed. The work is tracked in
#448 epic.
The detailed description of each crate is placed in its documentation at top
of its `lib.rs` file.
The detailed description of each crate is placed in its documentation at top of
its `lib.rs` file.
There are two main parts of our codebase: **EnsoGL library** and the **Enso
IDE application**. The crates used in common by those parts are put in `src
/rust/lib`, and should be documented at the top of their `lib.rs` file.
There are two main parts of our codebase: **EnsoGL library** and the **Enso IDE
application**. The crates used in common by those parts are put in
`src /rust/lib`, and should be documented at the top of their `lib.rs` file.
Other crates usually contains code shared by those two. The one noteworthy
is the **prelude** crate (`src/rust/prelude`) which gathers the commonly used
Other crates usually contains code shared by those two. The one noteworthy is
the **prelude** crate (`src/rust/prelude`) which gathers the commonly used
imports across all crates in our repository.
### EnsoGL (`src/rust/ensogl`)
@ -28,16 +28,16 @@ EnsoGL is a library providing fast 2D vector rendering engine with a rich set of
primitives and high-level GUI components. Its structure will be described after
the planned refactoring in #598.
### Enso IDE (`src/rust/ide`)
The Enso IDE crate contains entry point function of application, and
integrates two main parts of it:
* IDE View (`src/rust/ide/lib/view`) - The visual part of IDE. It contains
no logic and connections to backend - instead it delivers FRP endpoints to
be integrated with controllers. That design allow us to measure of vis-part
only performance.
* IDE Controllers (`src/rust/ide/lib/controller`) - The logic part of IDE,
that is synchronizing graph a text and communication with Engine. It
should not know anything about visual part. In the future we may consider
creating some sort of CLI for automatic integration tests.
The Enso IDE crate contains entry point function of application, and integrates
two main parts of it:
- IDE View (`src/rust/ide/lib/view`) - The visual part of IDE. It contains no
logic and connections to backend - instead it delivers FRP endpoints to be
integrated with controllers. That design allow us to measure of vis-part only
performance.
- IDE Controllers (`src/rust/ide/lib/controller`) - The logic part of IDE, that
is synchronizing graph a text and communication with Engine. It should not
know anything about visual part. In the future we may consider creating some
sort of CLI for automatic integration tests.

View File

@ -4,16 +4,16 @@ layout: style-guide title: Rust Style Guide category: style-guide tags: [style-g
# Rust Style Guide
We are using `rustfmt` for the basic formatting of our rust code, which is also checked on CI. We
have some additional guidelines for imports, naming, sections within files and naming which are
documented here.
We are using `rustfmt` for the basic formatting of our rust code, which is also
checked on CI. We have some additional guidelines for imports, naming, sections
within files and naming which are documented here.
## Styling rules
### Imports
Imports should be divided into 4 groups separated by blank lines. Items in the groups should be
sorted alphabetically.
Imports should be divided into 4 groups separated by blank lines. Items in the
groups should be sorted alphabetically.
```rust
// Group 1: sub-module definitions.
@ -40,12 +40,14 @@ use nalgebra::Vector3;
### Sections
Source files should be divided into sections. Section headers should be placed before each new "
concept" defined in a file. By "concept" we normally mean a structure with related implementations.
In case related implementations use some helper structs with very small implementations, these
helper structs may be defined in the same section. Moreover, the code in each section should be
divided into sub-sections, grouping related definitions. At least one section should be defined in a
file (if there is at least one struct definition as well). For example:
Source files should be divided into sections. Section headers should be placed
before each new " concept" defined in a file. By "concept" we normally mean a
structure with related implementations. In case related implementations use some
helper structs with very small implementations, these helper structs may be
defined in the same section. Moreover, the code in each section should be
divided into sub-sections, grouping related definitions. At least one section
should be defined in a file (if there is at least one struct definition as
well). For example:
```rust
// =================
@ -141,10 +143,11 @@ impl<OnChange: Callback0> HierarchicalTransform<OnChange> {
### Multiline Expressions
Most (preferably all) expressions should be single line. Multiline expressions are hard to read and
introduce noise in the code. Often, it is also an indicator of code that is not properly refactored.
Try to refactor parts of multiline expressions to well-named variables, and divide them to several
single-line expressions.
Most (preferably all) expressions should be single line. Multiline expressions
are hard to read and introduce noise in the code. Often, it is also an indicator
of code that is not properly refactored. Try to refactor parts of multiline
expressions to well-named variables, and divide them to several single-line
expressions.
Example of poorly formatted code:
@ -172,9 +175,9 @@ pub fn new() -> Self {
### Getters and Setters
Getters do not have the `get_` prefix, while setters do. If a setter is provided (method with
the `set_` prefix), a `mut` accessor should be provided as well. The correct way of defining getters
and setters is presented below:
Getters do not have the `get_` prefix, while setters do. If a setter is provided
(method with the `set_` prefix), a `mut` accessor should be provided as well.
The correct way of defining getters and setters is presented below:
```rust
fn field(&self) -> &Type {
@ -192,13 +195,14 @@ fn set_field(&mut self, val: Type) {
### Trait exporting
All names should be designed to be used in a qualified fashion. However, this makes one situation
tricky. In order to use methods defined in a trait, it has to be in scope. Consider a trait
`display::Object`. We want to use it as function bound like `fn test<T:display::Object>(t:T) {...}`,
and we also want to use methods defined in this trait (so it has to be in scope). In such a case,
`Clippy` warns that `display::Object` is unnecessary qualification and could be replaced simply by
`Object`, which is not what we want. Thus, in order to export traits, please always rename them
using the following convention:
All names should be designed to be used in a qualified fashion. However, this
makes one situation tricky. In order to use methods defined in a trait, it has
to be in scope. Consider a trait `display::Object`. We want to use it as
function bound like `fn test<T:display::Object>(t:T) {...}`, and we also want to
use methods defined in this trait (so it has to be in scope). In such a case,
`Clippy` warns that `display::Object` is unnecessary qualification and could be
replaced simply by `Object`, which is not what we want. Thus, in order to export
traits, please always rename them using the following convention:
```rust
/// Common traits.
@ -209,5 +213,6 @@ pub mod traits {
}
```
Having such a definition, we can import traits to scope using `use display::object::traits::*`, and
we would not have any warning about unnecessary qualification anymore.
Having such a definition, we can import traits to scope using
`use display::object::traits::*`, and we would not have any warning about
unnecessary qualification anymore.

View File

@ -10,6 +10,6 @@ This section contains detailed specification of Enso IDE from the user
perspective. The implementation is documented in rust code and in the crate's
`docs` directory.
* [**List of Shortcuts**](./shortcuts.md)
* [**Visualizations**](./visualizations.md)
* [**Searcher in Graph Editor**](./searcher.md)
- [**List of Shortcuts**](./shortcuts.md)
- [**Visualizations**](./visualizations.md)
- [**Searcher in Graph Editor**](./searcher.md)

View File

@ -10,12 +10,13 @@ tags: [product]
### Behaviour
The Searcher Panel can be brought to the screen in two different ways:
* when user starts to edit node's expression - the node becomes Searcher input
- when user starts to edit node's expression - the node becomes Searcher input
and panel appears below,
* when user press tab with mouse over Graph Editor Panel - the new Searcher
input appears with Searcher panel below. Additionally, if there is exactly
one node selected, the connection is displayed between the selected node
and the Searcher input.
- when user press tab with mouse over Graph Editor Panel - the new Searcher
input appears with Searcher panel below. Additionally, if there is exactly one
node selected, the connection is displayed between the selected node and the
Searcher input.
### Suggestion of Node Expressions
@ -27,7 +28,7 @@ connected to selection. The current implementation can be found in
### Suggestion Database
The `search/completion` method of Language Server returns a list of keys to
the Suggestion Database instead of the whole entries. The database is
retrieved by IDE on Project opening, and keeps it up to date. The Database
is implemented in `ide::model::suggestion_database` module.
The `search/completion` method of Language Server returns a list of keys to the
Suggestion Database instead of the whole entries. The database is retrieved by
IDE on Project opening, and keeps it up to date. The Database is implemented in
`ide::model::suggestion_database` module.

View File

@ -8,29 +8,34 @@ tags: [product,ui]
## General Assumptions
#### The <kbd>meta</kbd> key.
The <kbd>meta</kbd> key was introduced to make the shortcuts consistent across platforms.
It is defined as <kbd>command</kbd> on macOS, and as <kbd>ctrl</kbd> on Windows and Linux.
The <kbd>meta</kbd> key was introduced to make the shortcuts consistent across
platforms. It is defined as <kbd>command</kbd> on macOS, and as <kbd>ctrl</kbd>
on Windows and Linux.
#### Keyboard-only Workflow
The GUI and all shortcuts were designed in a way to allow both efficient mouse-only as well as
keyboard-only workflows. In most cases, there is a relation between mouse and keyboard shortcuts,
namely, the `left-mouse-button` corresponds to `enter`. For example, stepping into a node is done
by either double clicking the node, or just pressing the enter key.
The GUI and all shortcuts were designed in a way to allow both efficient
mouse-only as well as keyboard-only workflows. In most cases, there is a
relation between mouse and keyboard shortcuts, namely, the `left-mouse-button`
corresponds to `enter`. For example, stepping into a node is done by either
double clicking the node, or just pressing the enter key.
#### Missing / not working shortcuts
Some of the shortcuts presented below are marked with the :warning: icon, which means, that they are
planned, but not yet implemented. Feel free to contribute and help us implement them!
Shortcuts marked with the :bangbang: icon should work, but are reported to be broken and require
further investigation.
Some of the shortcuts presented below are marked with the :warning: icon, which
means, that they are planned, but not yet implemented. Feel free to contribute
and help us implement them!
Shortcuts marked with the :bangbang: icon should work, but are reported to be
broken and require further investigation.
## Graph Editor
#### General Shortcuts
| Shortcut | Action |
| -------- | ------ |
| ----------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| <kbd>cmd</kbd>+<kbd>alt</kbd>+<kbd>shift</kbd>+<kbd>t</kbd> | Toggle light/dark application style. Currently doesn't work properly, as the Theme Switcher is not created yet. (https://github.com/enso-org/ide/issues/795) |
| <kbd>ctrl</kbd>+<kbd>`</kbd> | Show Code Editor. Please note that the Code Editor implementation is in a very early stage and you should not use it. Even just openning it can cause errors in the IDE. Do not try using the graph editor while having the code editor tab openned. |
| <kbd>cmd</kbd>+<kbd>o</kbd> | Open project |
@ -43,36 +48,36 @@ further investigation.
| <kbd>ctrl</kbd>+<kbd>w</kbd> | Close the application (Windows, Linux) |
| :warning: <kbd>ctrl</kbd>+<kbd>p</kbd> | Toggle profiling mode |
#### Navigation
| Shortcut | Action |
| -------- | ------ |
| Drag gesture (two fingers) | Pan the scene.
| Pinch gesture (two fingers) | Zoom the scene.
| <kbd>MMB</kbd> drag | Pan the scene.
| <kbd>RMB</kbd> drag | Zoom the scene.
| <kbd>LMB</kbd> double press node name | Step into the node.
| :warning: <kbd>LMB</kbd> double press background | Step out of the current node.
| <kbd>enter</kbd> | Step in the last selected node.
| <kbd>alt</kbd>+<kbd>enter</kbd> | Step out of the current node.
| Shortcut | Action |
| ------------------------------------------------ | ------------------------------- |
| Drag gesture (two fingers) | Pan the scene. |
| Pinch gesture (two fingers) | Zoom the scene. |
| <kbd>MMB</kbd> drag | Pan the scene. |
| <kbd>RMB</kbd> drag | Zoom the scene. |
| <kbd>LMB</kbd> double press node name | Step into the node. |
| :warning: <kbd>LMB</kbd> double press background | Step out of the current node. |
| <kbd>enter</kbd> | Step in the last selected node. |
| <kbd>alt</kbd>+<kbd>enter</kbd> | Step out of the current node. |
#### Node Layout
| Shortcut | Action |
| -------- | ------ |
| ------------------------------------------ | ----------------------------------------------------------------- |
| <kbd>LMB</kbd> drag non-selected node name | Move the node to new position (dragging do not modify selection). |
| <kbd>LMB</kbd> drag selected node name | Move all selected nodes the node to new positions. |
#### Node Selection
| Shortcut | Action |
| --- | --- |
| ---------------------------------------------------------------------------------------------- | ---------------------------------------------------------- |
| <kbd>LMB</kbd> click node name | Deselect all nodes. Select the target node. |
| <kbd>LMB</kbd> click background | Deselect all nodes. |
| :warning: <kbd>LMB</kbd> drag background | Select nodes using selection-box. |
| <kbd>shift</kbd> + <kbd>LMB</kbd> click node name | Add / remove node to the selection group. |
| :warning: <kbd>shift</kbd> + <kbd>LMB</kbd> drag background | Add / remove nodes to the selection group. |
| :warning: <kbd>*-arrow</kbd> | Select node on the right side of the newest selected node. |
| :warning: <kbd>\*-arrow</kbd> | Select node on the right side of the newest selected node. |
| :warning: <kbd>cmd</kbd> + <kbd>a</kbd> | Select all nodes. |
| :warning: <kbd>escape</kbd> | Deselect all nodes (if not in a mode, like edit mode). |
| <kbd>shift</kbd> + <kbd>ctrl</kbd> + <kbd>LMB</kbd> click node name | Add node to the selection group. |
@ -82,10 +87,10 @@ further investigation.
| <kbd>shift</kbd> + <kbd>ctrl</kbd> + <kbd>alt</kbd> + <kbd>LMB</kbd> click node name | Inverse node selection. |
| :warning: <kbd>shift</kbd> + <kbd>ctrl</kbd> + <kbd>alt</kbd> + <kbd>LMB</kbd> drag background | Inverse nodes selection. |
#### Node Editing
| Shortcut | Action |
| -------- | ------ |
| ------------------------------------------------ | -------------------------------------------- |
| <kbd>tab</kbd> | Show / hide node searcher. |
| <kbd>backspace</kbd> or <kbd>delete</kbd> | Remove selected nodes. |
| <kbd>cmd</kbd>+<kbd>g</kbd> | Collapse (group) selected nodes. |
@ -93,27 +98,27 @@ further investigation.
| <kbd>meta</kbd>+<kbd>enter</kbd> | Start editing node expression. |
| <kbd>enter</kbd> or <kbd>LMB</kbd> on suggestion | Pick selected suggestion and commit editing. |
#### Visualization
| Shortcut | Action |
| -------- | ------ |
| ----------------------------------------- | ------------------------------------------------------------- |
| <kbd>space</kbd> | Toggle visualization visibility of the selected node. |
| <kbd>space</kbd> hold | Preview visualization of the selected node (hide on release). |
| :warning: <kbd>space</kbd> double press | Toggle visualization fullscreen mode |
| <kbd>ctrl</kbd> + <kbd>space</kbd> | Cycle visualizations of the selected node. |
| :bangbang: <kbd>cmd</kbd> + <kbd>\\</kbd> | Toggle documentation view visibility |
#### Visualizations Implementations
| Shortcut | Action |
| -------- | ------ |
| ------------------------------ | -------------------------------------------------- |
| <kbd>meta</kbd> + <kbd>a</kbd> | Show all points if available in visualization. |
| <kbd>meta</kbd> + <kbd>z</kbd> | Zoom into selection if available in visualization. |
#### Debug
| Shortcut | Action |
| -------- | ------ |
| ------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------ |
| <kbd>ctrl</kbd> + <kbd>alt</kbd> + <kbd>shift</kbd> + <kbd>i</kbd> | Open the developer console. |
| <kbd>ctrl</kbd> + <kbd>alt</kbd> + <kbd>shift</kbd> + <kbd>r</kbd> | Reload the visual interface. |
| <kbd>ctrl</kbd> + <kbd>alt</kbd> + <kbd>0 - 10</kbd> | Switch between debug rendering modes (0 is the normal mode). |

View File

@ -1,9 +1,10 @@
# What is a Self-XSS scam?
A Self-XSS scam tricks you into compromising your account by claiming to provide a way to log into
someone else's account, or some other kind of reward, after pasting a special code or link into your
web browser. Never copy and paste scripts into the developer console.
A Self-XSS scam tricks you into compromising your account by claiming to provide
a way to log into someone else's account, or some other kind of reward, after
pasting a special code or link into your web browser. Never copy and paste
scripts into the developer console.
This kind of scam can often include malicious software and can give the attacker access to your
account and your data. Read the following article to learn more:
This kind of scam can often include malicious software and can give the attacker
access to your account and your data. Read the following article to learn more:
https://en.wikipedia.org/wiki/Self-XSS.

View File

@ -4,8 +4,6 @@
"hoist": true
}
},
"packages": [
"lib/*"
],
"packages": ["lib/*"],
"version": "0.0.0"
}

View File

@ -12,27 +12,27 @@ function get_build_config() {
const build = get_build_config()
let config = {
name: "Enso",
description: "Enso Data Processing Environment.",
main: "index.js",
name: 'Enso',
description: 'Enso Data Processing Environment.',
main: 'index.js',
dependencies: {
"create-servers": "^3.1.0",
"electron-is-dev": "^1.1.0",
"enso-studio-common": "1.0.0",
"enso-studio-content": "1.0.0",
"enso-studio-icons": "1.0.0",
"yargs": "^15.3.0"
'create-servers': '^3.1.0',
'electron-is-dev': '^1.1.0',
'enso-studio-common': '1.0.0',
'enso-studio-content': '1.0.0',
'enso-studio-icons': '1.0.0',
yargs: '^15.3.0',
},
devDependencies: {
"compression-webpack-plugin": "^3.1.0",
"copy-webpack-plugin": "^5.1.1",
"devtron": "^1.4.0",
"electron": "11.1.1",
"electron-builder": "^22.10.5",
"crypto-js": "4.0.0",
"electron-notarize" : "1.0.0",
'compression-webpack-plugin': '^3.1.0',
'copy-webpack-plugin': '^5.1.1',
devtron: '^1.4.0',
electron: '11.1.1',
'electron-builder': '^22.10.5',
'crypto-js': '4.0.0',
'electron-notarize': '1.0.0',
},
scripts: {
@ -76,18 +76,14 @@ config.build = {
icon: `${paths.dist.root}/icons/png`,
category: 'Development',
},
files: [
{ from: paths.dist.content, to: '.' }
],
extraResources: [
{ from: paths.dist.bin, to: '.' , filter: ["!**.tar.gz", "!**.zip"]}
],
files: [{ from: paths.dist.content, to: '.' }],
extraResources: [{ from: paths.dist.bin, to: '.', filter: ['!**.tar.gz', '!**.zip'] }],
fileAssociations: [
{
ext: 'enso',
name: 'Enso Source File',
role: 'Editor',
}
},
],
directories: {
output: paths.dist.client,
@ -100,7 +96,7 @@ config.build = {
// are handled by us. More info:
// https://github.com/electron-userland/electron-builder/issues/2851
// https://github.com/electron-userland/electron-builder/issues/2900
differentialPackage: false
differentialPackage: false,
},
dmg: {
// Disables "block map" generation during electron building. Block maps
@ -116,7 +112,7 @@ config.build = {
// notarised application it will still be detected as trusted.
// For more details see step (4) at
// https://kilianvalkhof.com/2019/electron/notarizing-your-electron-application/
sign: false
sign: false,
},
publish: [],
afterAllArtifactBuild: 'tasks/computeHashes.js',

View File

@ -17,16 +17,12 @@ import paths from '../../../../../build/paths'
const child_process = require('child_process')
const fss = require('fs')
// =============
// === Paths ===
// =============
const root = Electron.app.getAppPath()
const resources = path.join(root, "..")
const resources = path.join(root, '..')
// FIXME default options parsed wrong
// https://github.com/yargs/yargs/issues/1590
@ -40,8 +36,6 @@ let windowCfg = {
height: 900,
}
// =============
// === Utils ===
// =============
@ -50,8 +44,7 @@ function capitalizeFirstLetter(string) {
return string.charAt(0).toUpperCase() + string.slice(1)
}
const execFile = util.promisify(child_process.execFile);
const execFile = util.promisify(child_process.execFile)
// The list of hosts that the app can access. They are required for
// user authentication to work.
@ -77,7 +70,7 @@ Arguments that follow the two dashes (\`--\`) will be passed to the backend proc
if IDE spawns backend, i.e. if '--backend false' has not been set.`
let optParser = yargs
.scriptName("")
.scriptName('')
.usage(usage)
.epilogue(epilogue)
.help()
@ -85,7 +78,6 @@ let optParser = yargs
.parserConfiguration({ 'populate--': true })
.strict()
// === Config Options ===
let configOptionsGroup = 'Config Options:'
@ -137,7 +129,7 @@ optParser.options('verbose', {
group: debugOptionsGroup,
describe: `Increase logs verbosity. Affects both IDE and the backend.`,
default: false,
type : `boolean`
type: `boolean`,
})
optParser.options('entry-point', {
@ -156,7 +148,6 @@ optParser.options('devtron', {
describe: 'Install the Devtron Developer Tools extension',
})
// === Style Options ===
let styleOptionsGroup = 'Style Options:'
@ -164,36 +155,35 @@ let styleOptionsGroup = 'Style Options:'
optParser.options('frame', {
group: styleOptionsGroup,
describe: 'Draw window frame. Defaults to `false` on MacOS and `true` otherwise.',
type : `boolean`
type: `boolean`,
})
optParser.options('vibrancy', {
group: styleOptionsGroup,
describe: 'Use the vibrancy effect',
default: false,
type : `boolean`
type: `boolean`,
})
optParser.options('window-size', {
group: styleOptionsGroup,
describe: `Set the window size [${windowCfg.width}x${windowCfg.height}]`,
requiresArg : true
requiresArg: true,
})
optParser.options('theme', {
group: styleOptionsGroup,
describe: 'Use the provided theme. Defaults to `light`.',
type : `string`
type: `string`,
})
optParser.options('node-labels', {
group: styleOptionsGroup,
describe: 'Show node labels. Defaults to `true`.',
default: true,
type : `boolean`
type: `boolean`,
})
// === Other Options ===
optParser.options('info', {
@ -205,19 +195,19 @@ optParser.options('version', {
})
optParser.options('crash-report-host', {
describe : 'The address of the server that will receive crash reports. ' +
describe:
'The address of the server that will receive crash reports. ' +
'Consists of a hostname, optionally followed by a ":" and a port number',
requiresArg: true,
default : cfg.defaultLogServerHost
default: cfg.defaultLogServerHost,
})
optParser.options('data-gathering', {
describe: 'Enable the sharing of any usage data',
type: 'boolean',
default : true
default: true,
})
// === Parsing ===
function parseCmdArgs() {
@ -232,7 +222,7 @@ let args = parseCmdArgs()
// borderless on Mac. See https://github.com/enso-org/ide/issues/1101 and
// https://github.com/electron/electron/issues/3647 for details.
if (args.frame === undefined) {
args.frame = (process.platform !== 'darwin')
args.frame = process.platform !== 'darwin'
}
if (args.theme === undefined) {
@ -251,8 +241,6 @@ if (args.windowSize) {
}
}
// ==================
// === Debug Info ===
// ==================
@ -289,11 +277,9 @@ async function getDebugInfo() {
async function printDebugInfo() {
let info = await getDebugInfo()
console.log(JSON.stringify(info, undefined, 4))
process.exit();
process.exit()
}
// ================
// === Security ===
// ================
@ -307,7 +293,9 @@ async function printDebugInfo() {
/// security features. Follow the link to learn more:
/// https://www.electronjs.org/docs/tutorial/security#11-verify-webview-options-before-creation
function secureWebPreferences(webPreferences) {
if(!webPreferences) { webPreferences = {} }
if (!webPreferences) {
webPreferences = {}
}
delete webPreferences.preload
delete webPreferences.preloadURL
delete webPreferences.nodeIntegration
@ -335,7 +323,6 @@ Electron.app.on('web-contents-created', (event,contents) => {
})
})
// === Prevent Navigation ===
/// Navigation is a common attack vector. If an attacker can convince your app to navigate away from
@ -352,7 +339,6 @@ Electron.app.on('web-contents-created', (event,contents) => {
})
})
// === Disable New Windows Creation ===
/// Much like navigation, the creation of new webContents is a common attack vector. Attackers
@ -367,8 +353,6 @@ Electron.app.on('web-contents-created', (event,contents) => {
})
})
// =======================
// === Project Manager ===
// =======================
@ -395,7 +379,9 @@ function projectManagerPath() {
*/
async function execProjectManager(args) {
let binPath = projectManagerPath()
return await execFile(binPath,args).catch(function(err) {throw err})
return await execFile(binPath, args).catch(function (err) {
throw err
})
}
/**
@ -414,11 +400,11 @@ function spawnProjectManager(args) {
let stdout = 'inherit'
let stderr = 'inherit'
let opts = {
stdio: [stdin,stdout,stderr]
stdio: [stdin, stdout, stderr],
}
let out = child_process.spawn(binPath, args, opts)
console.log(`Project Manager has been spawned, pid = ${out.pid}.`)
out.on('exit', (code) => {
out.on('exit', code => {
console.log(`Project Manager exited with code ${code}.`)
})
return out
@ -430,19 +416,17 @@ function runBackend() {
if (args.verbose === true) {
opts.push('-vv')
}
console.log("Starting the backend process with the following options:", opts)
console.log('Starting the backend process with the following options:', opts)
return spawnProjectManager(opts)
}
}
async function backendVersion() {
if (args.backend !== false) {
return await execProjectManager(['--version']).then((t) => t.stdout)
return await execProjectManager(['--version']).then(t => t.stdout)
}
}
// ============
// === Main ===
// ============
@ -456,7 +440,7 @@ let origin = null
async function main(args) {
setUserAgent()
runBackend()
console.log("Starting the IDE service.")
console.log('Starting the IDE service.')
if (args.server !== false) {
let serverCfg = Object.assign({}, args)
serverCfg.dir = root
@ -465,9 +449,9 @@ async function main(args) {
origin = `http://localhost:${server.port}`
}
if (args.window !== false) {
console.log("Starting the IDE client.")
console.log('Starting the IDE client.')
mainWindow = createWindow()
mainWindow.on("close", (evt) => {
mainWindow.on('close', evt => {
if (hideInsteadOfQuit) {
evt.preventDefault()
mainWindow.hide()
@ -495,7 +479,7 @@ function urlParamsFromObject(obj) {
let val = obj[key]
params.push(`${key}=${val}`)
}
return params.join("&")
return params.join('&')
}
function createWindow() {
@ -511,7 +495,7 @@ function createWindow() {
sandbox: true,
backgroundThrottling: false,
transparent: false,
titleBarStyle : 'default'
titleBarStyle: 'default',
}
if (args.dev) {
@ -550,8 +534,12 @@ function createWindow() {
verbose: args.verbose,
}
if (args.project) { urlCfg.project = args.project }
if (args.entryPoint) { urlCfg.entry = args.entryPoint }
if (args.project) {
urlCfg.project = args.project
}
if (args.entryPoint) {
urlCfg.entry = args.entryPoint
}
let params = urlParamsFromObject(urlCfg)
let address = `${origin}?${params}`
@ -574,8 +562,6 @@ function setupPermissions() {
)
}
// ==============
// === Events ===
// ==============
@ -596,16 +582,16 @@ Electron.app.on('ready', () => {
}
}
console.log("Frontend:")
console.log('Frontend:')
for (let name in versionInfo) {
let label = capitalizeFirstLetter(name)
let spacing = ' '.repeat(maxNameLen - name.length)
console.log(`${indent}${label}:${spacing} ${versionInfo[name]}`)
}
console.log("")
console.log("Backend:")
backendVersion().then((backend) => {
console.log('')
console.log('Backend:')
backendVersion().then(backend => {
if (!backend) {
console.log(`${indent}No backend available.`)
} else {
@ -630,8 +616,6 @@ if (process.platform === 'darwin') {
})
}
// =================
// === Shortcuts ===
// =================
@ -657,12 +641,12 @@ Electron.app.on('web-contents-created', (webContentsCreatedEvent, webContents) =
let quit_on_win = process.platform == 'win32' && (alt_f4 || ctrl_w)
let quit_on_lin = process.platform == 'linux' && (alt_f4 || ctrl_q || ctrl_w)
let quit = quit_on_mac || quit_on_win || quit_on_lin
if (quit) { Electron.app.quit() }
if (quit) {
Electron.app.quit()
}
})
})
// =============================
// === Deprecations & Fixmes ===
// =============================

View File

@ -1,22 +1,20 @@
const remote = require('electron').remote
let win;
let win
if (remote !== undefined) {
win = remote.getCurrentWindow()
}
if (win === undefined) {
console.warn("Could not get current window object for window startup animation.")
console.warn('Could not get current window object for window startup animation.')
}
// =============================
// === Window Show Animation ===
// =============================
function ease_in_out_quad(t) {
return t<.5 ? 2*t*t : 1 - (-2*t+2)*(-2*t+2) / 2
return t < 0.5 ? 2 * t * t : 1 - ((-2 * t + 2) * (-2 * t + 2)) / 2
}
function animate_show(target) {
@ -24,7 +22,9 @@ function animate_show(target) {
let opacity = 0
function show_step(timestamp) {
opacity += 0.02
if (opacity > 1) { opacity = 1 }
if (opacity > 1) {
opacity = 1
}
target.setOpacity(ease_in_out_quad(opacity))
if (opacity < 1) {
window.requestAnimationFrame(show_step)
@ -40,8 +40,6 @@ if (win !== undefined) {
window.showAnimation = animate_show(win)
}
// ===================
// === Debug Tools ===
// ===================

View File

@ -1,18 +1,14 @@
const crypto = require('crypto');
const fs = require('fs');
const glob = require('glob');
const crypto = require('crypto')
const fs = require('fs')
const glob = require('glob')
const paths = require('../../../../../build/paths')
// =================
// === Constants ===
// =================
const CHECKSUM_TYPE = 'sha256'
// ================
// === Checksum ===
// ================
@ -20,28 +16,28 @@ const CHECKSUM_TYPE = 'sha256'
/// The `type` argument can be one of `md5`, `sha1`, or `sha256`.
function getChecksum(path, type) {
return new Promise(function (resolve, reject) {
const hash = crypto.createHash(type);
const input = fs.createReadStream(path);
input.on('error', reject);
const hash = crypto.createHash(type)
const input = fs.createReadStream(path)
input.on('error', reject)
input.on('data', function (chunk) {
hash.update(chunk);
});
hash.update(chunk)
})
input.on('close', function () {
resolve(hash.digest('hex'));
});
});
resolve(hash.digest('hex'))
})
})
}
async function writeFileChecksum(path, type) {
let checksum = await getChecksum(path, type)
let targetPath = `${path}.${type}`
fs.writeFile(targetPath,checksum,'utf8',(err) => {
if (err) { throw err }
fs.writeFile(targetPath, checksum, 'utf8', err => {
if (err) {
throw err
}
})
}
// ================
// === Callback ===
// ================

View File

@ -1,25 +1,25 @@
/// This script will trigger the notarisation process for macOS and trigger our pre-processing
/// and signing of the engine.
require('dotenv').config();
const { notarize } = require('electron-notarize');
require('dotenv').config()
const { notarize } = require('electron-notarize')
exports.default = async function notarizing(context) {
const { electronPlatformName, appOutDir } = context;
const { electronPlatformName, appOutDir } = context
if (electronPlatformName !== 'darwin') {
return;
return
}
// We need to manually re-sign our build artifacts before notarisation.
// See the script for more information.
console.log(" • Performing additional signing of dependencies.")
await require("./signArchives").default()
console.log(' • Performing additional signing of dependencies.')
await require('./signArchives').default()
// Notarize the application.
const appName = context.packager.appInfo.productFilename;
console.log(" • Notarizing.")
const appName = context.packager.appInfo.productFilename
console.log(' • Notarizing.')
return await notarize({
appBundleId: 'com.enso.ide',
appPath: `${appOutDir}/${appName}.app`,
appleId: process.env.APPLEID,
appleIdPassword: process.env.APPLEIDPASS,
});
};
})
}

View File

@ -1,7 +1,5 @@
const { beforeSign } = require('./signArchives')
// ================
// === Callback ===
// ================

View File

@ -26,7 +26,7 @@ const ID = '"Developer ID Application: New Byte Order Sp. z o. o. (NM77WTZJFQ)"'
// Placeholder name for temporary archives.
const tmpArchive = 'temporary_archive.zip'
const GRAALVM = 'graalvm-ce-java11-21.1.0';
const GRAALVM = 'graalvm-ce-java11-21.1.0'
// Helper to execute a command in a given directory and return the output.
const run = (cmd, cwd) => child_process.execSync(cmd, { shell: true, cwd }).toString()
@ -36,8 +36,8 @@ function sign(targetPath, cwd) {
console.log(`Signing ${targetPath} in ${cwd}`)
const entitlements_path = path.resolve('./', 'entitlements.mac.plist')
return run(
`codesign -vvv --entitlements ${entitlements_path} --force --options=runtime `
+ `--sign ${ID} ${targetPath}`,
`codesign -vvv --entitlements ${entitlements_path} --force --options=runtime ` +
`--sign ${ID} ${targetPath}`,
cwd
)
}
@ -108,8 +108,7 @@ function signArchive(archivePath, archiveName, binPaths) {
// message provided by Apple and can then be added here.
const toSign = [
{
jarDir:
`enso/dist/${ENGINE_VERSION}/lib/Standard/Database/${ENGINE_VERSION}/polyglot/java`,
jarDir: `enso/dist/${ENGINE_VERSION}/lib/Standard/Database/${ENGINE_VERSION}/polyglot/java`,
jarName: 'sqlite-jdbc-3.34.0.jar',
jarContent: [
'org/sqlite/native/Mac/aarch64/libsqlitejdbc.jnilib',
@ -117,8 +116,7 @@ const toSign = [
],
},
{
jarDir:
`enso/dist/${ENGINE_VERSION}/component`,
jarDir: `enso/dist/${ENGINE_VERSION}/component`,
jarName: 'runner.jar',
jarContent: [
'org/sqlite/native/Mac/x86_64/libsqlitejdbc.jnilib',
@ -126,116 +124,97 @@ const toSign = [
],
},
{
jarDir:
`enso/runtime/${GRAALVM}/Contents/Home/jmods`,
jarDir: `enso/runtime/${GRAALVM}/Contents/Home/jmods`,
jarName: 'jdk.jartool.jmod',
jarContent: ['bin/jarsigner', 'bin/jar'],
},
{
jarDir:
`enso/runtime/${GRAALVM}/Contents/Home/jmods`,
jarDir: `enso/runtime/${GRAALVM}/Contents/Home/jmods`,
jarName: 'jdk.jdeps.jmod',
jarContent: ['bin/javap', 'bin/jdeprscan', 'bin/jdeps'],
},
{
jarDir:
`enso/runtime/${GRAALVM}/Contents/Home/jmods`,
jarDir: `enso/runtime/${GRAALVM}/Contents/Home/jmods`,
jarName: 'jdk.jstatd.jmod',
jarContent: ['bin/jstatd'],
},
{
jarDir:
`enso/runtime/${GRAALVM}/Contents/Home/jmods`,
jarDir: `enso/runtime/${GRAALVM}/Contents/Home/jmods`,
jarName: 'jdk.pack.jmod',
jarContent: ['bin/unpack200', 'bin/pack200'],
},
{
jarDir:
`enso/runtime/${GRAALVM}/Contents/Home/jmods`,
jarDir: `enso/runtime/${GRAALVM}/Contents/Home/jmods`,
jarName: 'jdk.hotspot.agent.jmod',
jarContent: ['bin/jhsdb'],
},
{
jarDir:
`enso/runtime/${GRAALVM}/Contents/Home/jmods`,
jarDir: `enso/runtime/${GRAALVM}/Contents/Home/jmods`,
jarName: 'jdk.jfr.jmod',
jarContent: ['bin/jfr'],
},
{
jarDir:
`enso/runtime/${GRAALVM}/Contents/Home/jmods`,
jarDir: `enso/runtime/${GRAALVM}/Contents/Home/jmods`,
jarName: 'jdk.rmic.jmod',
jarContent: ['bin/rmic'],
},
{
jarDir:
`enso/runtime/${GRAALVM}/Contents/Home/jmods`,
jarDir: `enso/runtime/${GRAALVM}/Contents/Home/jmods`,
jarName: 'java.rmi.jmod',
jarContent: ['bin/rmid', 'bin/rmiregistry'],
},
{
jarDir:
`enso/runtime/${GRAALVM}/Contents/Home/jmods`,
jarDir: `enso/runtime/${GRAALVM}/Contents/Home/jmods`,
jarName: 'java.base.jmod',
jarContent: ['bin/java', 'bin/keytool', 'lib/jspawnhelper'],
},
{
jarDir:
`enso/runtime/${GRAALVM}/Contents/Home/jmods`,
jarDir: `enso/runtime/${GRAALVM}/Contents/Home/jmods`,
jarName: 'jdk.jlink.jmod',
jarContent: ['bin/jmod', 'bin/jlink', 'bin/jimage'],
},
{
jarDir:
`enso/runtime/${GRAALVM}/Contents/Home/jmods`,
jarDir: `enso/runtime/${GRAALVM}/Contents/Home/jmods`,
jarName: 'jdk.scripting.nashorn.shell.jmod',
jarContent: ['bin/jjs'],
},
{
jarDir:
`enso/runtime/${GRAALVM}/Contents/Home/jmods`,
jarDir: `enso/runtime/${GRAALVM}/Contents/Home/jmods`,
jarName: 'jdk.jcmd.jmod',
jarContent: ['bin/jstack', 'bin/jcmd', 'bin/jps', 'bin/jmap', 'bin/jstat', 'bin/jinfo'],
},
{
jarDir:
`enso/runtime/${GRAALVM}/Contents/Home/jmods`,
jarDir: `enso/runtime/${GRAALVM}/Contents/Home/jmods`,
jarName: 'jdk.jshell.jmod',
jarContent: ['bin/jshell'],
},
{
jarDir:
`enso/runtime/${GRAALVM}/Contents/Home/jmods`,
jarDir: `enso/runtime/${GRAALVM}/Contents/Home/jmods`,
jarName: 'jdk.compiler.jmod',
jarContent: ['bin/javac', 'bin/serialver'],
},
{
jarDir:
`enso/runtime/${GRAALVM}/Contents/Home/jmods`,
jarDir: `enso/runtime/${GRAALVM}/Contents/Home/jmods`,
jarName: 'java.scripting.jmod',
jarContent: ['bin/jrunscript'],
},
{
jarDir:
`enso/runtime/${GRAALVM}/Contents/Home/jmods`,
jarDir: `enso/runtime/${GRAALVM}/Contents/Home/jmods`,
jarName: 'jdk.jdi.jmod',
jarContent: ['bin/jdb'],
},
{
jarDir:
`enso/runtime/${GRAALVM}/Contents/Home/jmods`,
jarDir: `enso/runtime/${GRAALVM}/Contents/Home/jmods`,
jarName: 'jdk.javadoc.jmod',
jarContent: ['bin/javadoc'],
},
{
jarDir:
`enso/runtime/${GRAALVM}/Contents/Home/jmods`,
jarDir: `enso/runtime/${GRAALVM}/Contents/Home/jmods`,
jarName: 'jdk.jconsole.jmod',
jarContent: ['bin/jconsole'],
},
{
jarDir:
`enso/runtime/${GRAALVM}/Contents/Home/jmods`,
jarDir: `enso/runtime/${GRAALVM}/Contents/Home/jmods`,
jarName: 'jdk.javadoc.jmod',
jarContent: ['bin/javadoc'],
},
@ -260,9 +239,7 @@ const extra = [
]
// The list of readonly files in the GraalVM distribution.
const readonly = [
`enso/runtime/${GRAALVM}/Contents/Home/lib/server/classes.jsa`,
]
const readonly = [`enso/runtime/${GRAALVM}/Contents/Home/lib/server/classes.jsa`]
function beforeSign() {
for (let file of readonly) {

View File

@ -10,7 +10,7 @@ module.exports = {
index: path.resolve(thisPath, 'src', 'index.js'),
},
mode: 'production',
target: "electron-main",
target: 'electron-main',
output: {
path: path.resolve(distPath, 'content'),
filename: '[name].js',
@ -19,12 +19,12 @@ module.exports = {
new Copy([
{
from: path.resolve(thisPath, 'package.json'),
to : path.resolve(distPath,'content','package.json')
to: path.resolve(distPath, 'content', 'package.json'),
},
{
from: path.resolve(thisPath, 'src', 'preload.js'),
to : path.resolve(distPath,'content','preload.js')
}
to: path.resolve(distPath, 'content', 'preload.js'),
},
]),
],
performance: {

View File

@ -1,6 +1,6 @@
let config = {
version: "1.0.0",
name: "enso-studio-common",
version: '1.0.0',
name: 'enso-studio-common',
}
module.exports = { config }

View File

@ -6,13 +6,13 @@
// =================
export function ease_in_out_cubic(t) {
return t<.5 ? 4*t*t*t : 1 - (-2*t+2) * (-2*t+2) * (-2*t+2) / 2
return t < 0.5 ? 4 * t * t * t : 1 - ((-2 * t + 2) * (-2 * t + 2) * (-2 * t + 2)) / 2
}
export function ease_in_out_quad(t) {
return t<.5 ? 2*t*t : 1 - (-2*t+2)*(-2*t+2) / 2
return t < 0.5 ? 2 * t * t : 1 - ((-2 * t + 2) * (-2 * t + 2)) / 2
}
export function ease_out_quart(t) {
return 1-(--t)*t*t*t
return 1 - --t * t * t * t
}

View File

@ -3,14 +3,12 @@ import * as html_utils from './html_utils'
import * as math from './math'
import * as svg from './svg'
// =========================
// === ProgressIndicator ===
// =========================
let bg_color = "rgb(249,250,251)"
let loader_color = "#303030"
let bg_color = 'rgb(249,250,251)'
let loader_color = '#303030'
let top_layer_index = 1000
/// Visual representation of the loader.
@ -38,9 +36,9 @@ export class ProgressIndicator {
progress_bar.innerHTML = progress_bar_svg
center.appendChild(progress_bar)
this.progress_indicator = document.getElementById("progress_indicator")
this.progress_indicator_mask = document.getElementById("progress_indicator_mask")
this.progress_indicator_corner = document.getElementById("progress_indicator_corner")
this.progress_indicator = document.getElementById('progress_indicator')
this.progress_indicator_mask = document.getElementById('progress_indicator_mask')
this.progress_indicator_corner = document.getElementById('progress_indicator_corner')
this.set(0)
this.set_opacity(0)
@ -48,7 +46,9 @@ export class ProgressIndicator {
if (cfg.use_loader) {
this.initialized = this.animate_show()
} else {
this.initialized = new Promise((resolve) => {resolve()})
this.initialized = new Promise(resolve => {
resolve()
})
}
this.animate_rotation()
this.destroyed = false
@ -64,14 +64,21 @@ export class ProgressIndicator {
let mid_radius = (inner_radius + outer_radius) / 2
let bar_width = outer_radius - inner_radius
return svg.new_svg(width,height,`
return svg.new_svg(
width,
height,
`
<defs>
<g id="progress_bar">
<circle fill="${loader_color}" r="${outer_radius}" />
<circle fill="${bg_color}" r="${inner_radius}" />
<path fill="${bg_color}" opacity="${alpha}" id="progress_indicator_mask" />
<circle fill="${loader_color}" r="${bar_width/2}" id="progress_indicator_corner" />
<circle fill="${loader_color}" r="${bar_width/2}" cy="-${mid_radius}" />
<circle fill="${loader_color}" r="${
bar_width / 2
}" id="progress_indicator_corner" />
<circle fill="${loader_color}" r="${
bar_width / 2
}" cy="-${mid_radius}" />
</g>
</defs>
<g transform="translate(${width / 2},${height / 2})">
@ -79,7 +86,8 @@ export class ProgressIndicator {
<use xlink:href="#progress_bar"></use>
</g>
</g>
`)
`
)
}
/// Destroys the component. Removes it from the stage and destroys attached callbacks.
@ -95,19 +103,19 @@ export class ProgressIndicator {
let angle_span = max_angle - min_angle
let mask_angle = (1 - value) * angle_span - min_angle
let corner_pos = math.polar_to_cartesian(54, -mask_angle)
this.progress_indicator_mask.setAttribute("d", svg.arc(128, -mask_angle))
this.progress_indicator_corner.setAttribute("cx", corner_pos.x)
this.progress_indicator_corner.setAttribute("cy", corner_pos.y)
this.progress_indicator_mask.setAttribute('d', svg.arc(128, -mask_angle))
this.progress_indicator_corner.setAttribute('cx', corner_pos.x)
this.progress_indicator_corner.setAttribute('cy', corner_pos.y)
}
/// Set the opacity of the loader.
set_opacity(val) {
this.progress_indicator.setAttribute("opacity",val)
this.progress_indicator.setAttribute('opacity', val)
}
/// Set the rotation of the loader (angles).
set_rotation(val) {
this.progress_indicator.setAttribute("transform",`rotate(${val},0,0)`)
this.progress_indicator.setAttribute('transform', `rotate(${val},0,0)`)
}
/// Start show animation. It is used after the loader is created.
@ -116,7 +124,9 @@ export class ProgressIndicator {
return new Promise(function (resolve, reject) {
let alpha = 0
function show_step() {
if (alpha > 1) { alpha = 1 }
if (alpha > 1) {
alpha = 1
}
indicator.set_opacity(animation.ease_in_out_quad(alpha))
alpha += 0.02
if (alpha < 1) {
@ -144,8 +154,6 @@ export class ProgressIndicator {
}
}
// ==============
// === Loader ===
// ==============
@ -163,7 +171,9 @@ export class Loader {
let self = this
this.done_resolve = null
this.done = new Promise((resolve) => {self.done_resolve = resolve})
this.done = new Promise(resolve => {
self.done_resolve = resolve
})
for (let resource of resources) {
this.total_bytes += parseInt(resource.headers.get('Content-Length'))
@ -171,7 +181,9 @@ export class Loader {
}
if (Number.isNaN(this.total_bytes)) {
console.error("Loader error. Server is not configured to send the 'Content-Length' metadata.")
console.error(
"Loader error. Server is not configured to send the 'Content-Length' metadata."
)
this.total_bytes = 0
}
}
@ -210,7 +222,9 @@ export class Loader {
let indicator_progress = this.value() * this.cap_progress_at
this.indicator.set(indicator_progress)
if (this.is_done()) { this.done_resolve() }
if (this.is_done()) {
this.done_resolve()
}
}
/// Download percentage value.
@ -239,7 +253,7 @@ export class Loader {
return new WritableStream({
write(t) {
loader.on_receive(t.length)
}
},
})
}
}

View File

@ -1,21 +1,19 @@
/// This module defines a common math operations.
// ============
// === Math ===
// ============
/// Converts the polar coordinates to cartesian ones.
export function polar_to_cartesian(radius, angle_degrees) {
let angle = (angle_degrees-90) * Math.PI / 180.0
let angle = ((angle_degrees - 90) * Math.PI) / 180.0
return {
x: radius * Math.cos(angle),
y : radius * Math.sin(angle)
y: radius * Math.sin(angle),
}
}
/// Format bytes as megabytes with a single precision number.
export function format_mb(bytes) {
return Math.round(10 * bytes / (1024 * 1024)) / 10
return Math.round((10 * bytes) / (1024 * 1024)) / 10
}

View File

@ -4,8 +4,6 @@ import * as mime from 'mime-types'
import * as path from 'path'
import * as portfinder from 'portfinder'
// ============
// === Port ===
// ============
@ -19,8 +17,6 @@ async function findPort(cfg) {
}
}
// ==============
// === Server ===
// ==============
@ -35,22 +31,28 @@ class Server {
this.dir = cfg.dir
this.port = cfg.port
this.fallback = cfg.fallback
this.server = createServers({
this.server = createServers(
{
http: this.port,
handler: function (request, response) {
self.process(request.url, response)
}
},
},
function (errs) {
if (errs) { return console.log(errs.http) }
if (errs) {
return console.log(errs.http)
}
console.log(`Server started on port ${this.port}.`)
console.log(`Serving files from '${process.cwd()}/${this.dir}'.`)
}.bind(this))
}.bind(this)
)
}
process(resource, response) {
let resource_file = `${this.dir}${resource}`
fs.readFile(resource_file, function (err,data) {
fs.readFile(
resource_file,
function (err, data) {
if (err) {
let fallback = this.fallback
if (fallback) {
@ -70,7 +72,8 @@ class Server {
response.writeHead(200)
response.end(data)
}
}.bind(this))
}.bind(this)
)
}
}

View File

@ -2,8 +2,6 @@
import * as math from './math'
// ===========
// === SVG ===
// ===========
@ -27,6 +25,6 @@ export function arc(radius, end_angle){
}
let start = math.polar_to_cartesian(radius, end_angle)
let end = math.polar_to_cartesian(radius, start_angle)
let large_arc = end_angle - start_angle <= 180 ? "0" : "1"
let large_arc = end_angle - start_angle <= 180 ? '0' : '1'
return `M 0 0 L ${start.x} ${start.y} A ${radius} ${radius} 0 ${large_arc} 0 ${end.x} ${end.y}`
}

View File

@ -1,27 +1,27 @@
let config = {
name: "enso-studio-content",
version: "1.0.0",
name: 'enso-studio-content',
version: '1.0.0',
scripts: {
"build": "npx webpack",
"watch": "npx webpack-dev-server"
build: 'npx webpack',
watch: 'npx webpack-dev-server',
},
dependencies: {
"enso-studio-common": "1.0.0",
"firebase": "^8.6.8",
"firebaseui": "^4.8.0",
"copy-webpack-plugin": "^5.1.1",
"html-loader": "^1.3.2",
"mixpanel-browser": "2.40.1"
'enso-studio-common': '1.0.0',
firebase: '^8.6.8',
firebaseui: '^4.8.0',
'copy-webpack-plugin': '^5.1.1',
'html-loader': '^1.3.2',
'mixpanel-browser': '2.40.1',
},
devDependencies: {
"compression-webpack-plugin": "^3.1.0",
"copy-webpack-plugin": "^5.1.1",
"yaml-loader": "^0.6.0",
"ts-loader": "^8.0.3",
"typescript": "^4.0.2",
"webpack": "^4.44.1",
"webpack-cli": "^3.3.12"
}
'compression-webpack-plugin': '^3.1.0',
'copy-webpack-plugin': '^5.1.1',
'yaml-loader': '^0.6.0',
'ts-loader': '^8.0.3',
typescript: '^4.0.2',
webpack: '^4.44.1',
'webpack-cli': '^3.3.12',
},
}
module.exports = { config }

View File

@ -1,37 +1,42 @@
@font-face {
font-family: 'Source Code Pro';
font-family: "Source Code Pro";
font-style: normal;
font-weight: 300;
font-display: swap;
src: url(https://fonts.gstatic.com/s/sourcecodepro/v14/HI_XiYsKILxRpg3hIP6sJ7fM7PqtlsnztA.ttf) format('truetype');
src: url(https://fonts.gstatic.com/s/sourcecodepro/v14/HI_XiYsKILxRpg3hIP6sJ7fM7PqtlsnztA.ttf)
format("truetype");
}
@font-face {
font-family: 'Source Code Pro';
font-family: "Source Code Pro";
font-style: normal;
font-weight: 400;
font-display: swap;
src: url(https://fonts.gstatic.com/s/sourcecodepro/v14/HI_SiYsKILxRpg3hIP6sJ7fM7PqVOg.ttf) format('truetype');
src: url(https://fonts.gstatic.com/s/sourcecodepro/v14/HI_SiYsKILxRpg3hIP6sJ7fM7PqVOg.ttf)
format("truetype");
}
@font-face {
font-family: 'Source Code Pro';
font-family: "Source Code Pro";
font-style: normal;
font-weight: 500;
font-display: swap;
src: url(https://fonts.gstatic.com/s/sourcecodepro/v14/HI_XiYsKILxRpg3hIP6sJ7fM7PqtzsjztA.ttf) format('truetype');
src: url(https://fonts.gstatic.com/s/sourcecodepro/v14/HI_XiYsKILxRpg3hIP6sJ7fM7PqtzsjztA.ttf)
format("truetype");
}
@font-face {
font-family: 'Source Code Pro';
font-family: "Source Code Pro";
font-style: normal;
font-weight: 600;
font-display: swap;
src: url(https://fonts.gstatic.com/s/sourcecodepro/v14/HI_XiYsKILxRpg3hIP6sJ7fM7Pqt4s_ztA.ttf) format('truetype');
src: url(https://fonts.gstatic.com/s/sourcecodepro/v14/HI_XiYsKILxRpg3hIP6sJ7fM7Pqt4s_ztA.ttf)
format("truetype");
}
@font-face {
font-family: 'Source Code Pro';
font-family: "Source Code Pro";
font-style: normal;
font-weight: 700;
font-display: swap;
src: url(https://fonts.gstatic.com/s/sourcecodepro/v14/HI_XiYsKILxRpg3hIP6sJ7fM7Pqths7ztA.ttf) format('truetype');
src: url(https://fonts.gstatic.com/s/sourcecodepro/v14/HI_XiYsKILxRpg3hIP6sJ7fM7Pqths7ztA.ttf)
format("truetype");
}
.enso.docs {
font-family: Causten, DejaVuSansMonoBook, sans-serif;
@ -60,7 +65,7 @@
font-size: 14px;
padding: 1px 0px 2px;
margin-top: 10px;
color: #4EA5FD;
color: #4ea5fd;
-webkit-box-decoration-break: clone;
}
.enso.docs .doc-copy-btn {
@ -164,7 +169,7 @@
line-height: 1.35;
box-decoration-break: clone;
-webkit-box-decoration-break: clone;
background-color: #E7E9EB;
background-color: #e7e9eb;
}
.light-theme .enso.docs .tag .details {
font-weight: 700;
@ -172,7 +177,7 @@
.light-theme .enso.docs .important,
.light-theme .enso.docs .info,
.light-theme .enso.docs .example {
background-color: #E7E9EB;
background-color: #e7e9eb;
border-radius: 12px;
padding: 15px;
}

View File

@ -26,7 +26,7 @@
font-size: 14px;
padding: 1px 0px 2px;
margin-top: 10px;
color: #4EA5FD;
color: #4ea5fd;
-webkit-box-decoration-break: clone;
}
.doc-copy-btn {
@ -136,7 +136,7 @@
line-height: 1.35;
box-decoration-break: clone;
-webkit-box-decoration-break: clone;
background-color: #E7E9EB;
background-color: #e7e9eb;
}
.details {
font-weight: 700;
@ -145,7 +145,7 @@
.important,
.info,
.example {
background-color: #E7E9EB;
background-color: #e7e9eb;
border-radius: 12px;
padding: 15px;
.summary {

View File

@ -1,12 +1,14 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta charset="utf-8" />
<!-- https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP -->
<!-- FIXME https://github.com/validator/validator/issues/917 -->
<!-- FIXME Security Vulnerabilities: https://github.com/enso-org/ide/issues/226 -->
<!-- NOTE `frame-src` section of `http-equiv` required only for authorization -->
<meta http-equiv="Content-Security-Policy" content="
<meta
http-equiv="Content-Security-Policy"
content="
default-src 'self';
frame-src 'self' data: https://accounts.google.com https://enso-org.firebaseapp.com;
script-src 'self' 'unsafe-eval' data: https://*;
@ -16,7 +18,9 @@
img-src 'self' blob: data: https://*;
font-src 'self' data: https://*"
/>
<meta name="viewport" content="
<meta
name="viewport"
content="
width=device-width,
initial-scale = 1.0,
maximum-scale = 1.0,
@ -25,7 +29,11 @@
<title>Enso</title>
<link rel="stylesheet" href="/assets/style.css" />
<link rel="stylesheet" href="/assets/docsStyle.css" />
<link type="text/css" rel="stylesheet" href="https://www.gstatic.com/firebasejs/ui/4.8.0/firebase-ui-auth.css" />
<link
type="text/css"
rel="stylesheet"
href="https://www.gstatic.com/firebasejs/ui/4.8.0/firebase-ui-auth.css"
/>
<script type="module" src="/assets/index.js" defer></script>
<script type="module" src="/assets/run.js" defer></script>
</head>

View File

@ -1,6 +1,6 @@
/// This module defines the Project Manager endpoint.
const PROJECT_MANAGER_ENDPOINT = "ws://127.0.0.1:30535"
const PROJECT_MANAGER_ENDPOINT = 'ws://127.0.0.1:30535'
const MISSING_COMPONENT_ACTION_INSTALL = 'Install'
@ -8,7 +8,6 @@ const MISSING_COMPONENT_ACTION_INSTALL = 'Install'
* A WebSocket endpoint to the project manager.
*/
class ProjectManager {
protected readonly connection_url: string
constructor(connection_url: string) {
@ -23,12 +22,11 @@ class ProjectManager {
* Get the projects list.
*/
listProjects(): any {
const req =
{
jsonrpc: "2.0",
const req = {
jsonrpc: '2.0',
id: 0,
method: "project/list",
params: {}
method: 'project/list',
params: {},
}
const ws = new WebSocket(this.connection_url)
@ -59,14 +57,13 @@ class ProjectManager {
}
if (template !== undefined) {
// @ts-ignore
params["projectTemplate"] = template
params['projectTemplate'] = template
}
const req =
{
jsonrpc: "2.0",
const req = {
jsonrpc: '2.0',
id: 0,
method: "project/create",
params: params
method: 'project/create',
params: params,
}
const ws = new WebSocket(this.connection_url)
@ -74,10 +71,10 @@ class ProjectManager {
ws.onopen = () => {
ws.send(JSON.stringify(req))
}
ws.onmessage = (event) => {
ws.onmessage = event => {
resolve(JSON.parse(event.data))
}
ws.onerror = (error) => {
ws.onerror = error => {
reject(error)
}
}).finally(() => ws.close())

View File

@ -11,10 +11,8 @@
@font-face {
font-family: "Causten";
src: url("/assets/fonts/CaustenExtraLight/font.woff2")
format("woff2"),
url("/assets/fonts/CaustenExtraLight/font.woff")
format("woff");
src: url("/assets/fonts/CaustenExtraLight/font.woff2") format("woff2"),
url("/assets/fonts/CaustenExtraLight/font.woff") format("woff");
font-style: normal;
font-weight: 200;
font-display: block;
@ -22,10 +20,8 @@
@font-face {
font-family: "Causten";
src: url("/assets/fonts/CaustenLight/font.woff2")
format("woff2"),
url("/assets/fonts/CaustenLight/font.woff")
format("woff");
src: url("/assets/fonts/CaustenLight/font.woff2") format("woff2"),
url("/assets/fonts/CaustenLight/font.woff") format("woff");
font-style: normal;
font-weight: 300;
font-display: block;
@ -33,10 +29,8 @@
@font-face {
font-family: "Causten";
src: url("/assets/fonts/CaustenRegular/font.woff2")
format("woff2"),
url("/assets/fonts/CaustenRegular/font.woff")
format("woff");
src: url("/assets/fonts/CaustenRegular/font.woff2") format("woff2"),
url("/assets/fonts/CaustenRegular/font.woff") format("woff");
font-style: normal;
font-weight: 400;
font-display: block;
@ -44,10 +38,8 @@
@font-face {
font-family: "Causten";
src: url("/assets/fonts/CaustenMedium/font.woff2")
format("woff2"),
url("/assets/fonts/CaustenMedium/font.woff")
format("woff");
src: url("/assets/fonts/CaustenMedium/font.woff2") format("woff2"),
url("/assets/fonts/CaustenMedium/font.woff") format("woff");
font-style: normal;
font-weight: 500;
font-display: block;
@ -55,10 +47,8 @@
@font-face {
font-family: "Causten";
src: url("/assets/fonts/CaustenSemiBold/font.woff2")
format("woff2"),
url("/assets/fonts/CaustenSemiBold/font.woff")
format("woff");
src: url("/assets/fonts/CaustenSemiBold/font.woff2") format("woff2"),
url("/assets/fonts/CaustenSemiBold/font.woff") format("woff");
font-style: normal;
font-weight: 600;
font-display: block;
@ -66,10 +56,8 @@
@font-face {
font-family: "Causten";
src: url("/assets/fonts/CaustenBold/font.woff2")
format("woff2"),
url("/assets/fonts/CaustenBold/font.woff")
format("woff");
src: url("/assets/fonts/CaustenBold/font.woff2") format("woff2"),
url("/assets/fonts/CaustenBold/font.woff") format("woff");
font-style: normal;
font-weight: 700;
font-display: block;
@ -77,10 +65,8 @@
@font-face {
font-family: "Causten";
src: url("/assets/fonts/CaustenExtraBold/font.woff2")
format("woff2"),
url("/assets/fonts/CaustenExtraBold/font.woff")
format("woff");
src: url("/assets/fonts/CaustenExtraBold/font.woff2") format("woff2"),
url("/assets/fonts/CaustenExtraBold/font.woff") format("woff");
font-style: normal;
font-weight: 800;
font-display: block;
@ -88,10 +74,8 @@
@font-face {
font-family: "Causten";
src: url("/assets/fonts/CaustenBlack/font.woff2")
format("woff2"),
url("/assets/fonts/CaustenBlack/font.woff")
format("woff");
src: url("/assets/fonts/CaustenBlack/font.woff2") format("woff2"),
url("/assets/fonts/CaustenBlack/font.woff") format("woff");
font-style: normal;
font-weight: 900;
font-display: block;
@ -99,7 +83,8 @@
/* End of fonts */
html, body {
html,
body {
height: 100vh;
}
@ -274,12 +259,12 @@ body {
.templates-view .side-menu ul img {
width: 14px;
padding: 8px;
background-color: #4180F1;
background-color: #4180f1;
border-radius: 5px;
}
.templates-view .side-menu li#projects-list-new-project img {
background-color: #EFEFEF;
background-color: #efefef;
}
.templates-view .content {

View File

@ -1,5 +1,10 @@
<div id="templates-view" class="templates-view">
<div id="templates-status-box" style="color: DarkSalmon; text-align: center; visibility: hidden;">Hidden</div>
<div
id="templates-status-box"
style="color: DarkSalmon; text-align: center; visibility: hidden"
>
Hidden
</div>
<div class="container">
<aside class="side-menu">
<h2>Your projects</h2>
@ -16,26 +21,24 @@
<div class="cards">
<div class="row">
<div id="card-spreadsheets" class="card card-spreadsheets">
<img
src="/assets/spreadsheets.png"
/>
<img src="/assets/spreadsheets.png" />
<h3>Combine spreadsheets</h3>
<p>
Glue multiple spreadsheets together to analyse all your data at once.
Glue multiple spreadsheets together to analyse all your data at
once.
</p>
</div>
<div id="card-geo" class="card card-geo">
<h3>Geospatial analysis</h3>
<p>
Learn where to open a coffee shop to maximize your income.
</p>
<p>Learn where to open a coffee shop to maximize your income.</p>
</div>
</div>
<div class="row">
<div id="card-visualize" class="card card-visualize">
<h3>Analyze GitHub stars</h3>
<p>
Find out which of Enso's repositories are most popular over time.
Find out which of Enso's repositories are most popular over
time.
</p>
</div>
</div>

View File

@ -11,11 +11,7 @@ const CARD_SPREADSHEETS = 'card-spreadsheets'
const CARD_GEO = 'card-geo'
const CARD_VISUALIZE = 'card-visualize'
const ALL_CARDS = [
CARD_SPREADSHEETS,
CARD_GEO,
CARD_VISUALIZE,
]
const ALL_CARDS = [CARD_SPREADSHEETS, CARD_GEO, CARD_VISUALIZE]
/**
* The sore for hidden elements.
@ -46,7 +42,7 @@ async function loadTemplatesView(openProject: (project: string) => void): Promis
try {
await loadProjectsList(openProject)
} catch (error) {
displayStatusBox("Failed to load projects.")
displayStatusBox('Failed to load projects.')
}
setTemplateCardHandlers(openProject)
@ -118,15 +114,14 @@ async function loadProjectsList(openProject: (project: string) => void): Promise
})
.catch((error: any) => {
console.error('onclick', PROJECTS_LIST_NEW_PROJECT, error)
displayStatusBox("Failed to create a new project.")
displayStatusBox('Failed to create a new project.')
})
}
const projectsListResult = await PM.listProjects()
const projectsList = projectsListResult
.result
.projects
.map((project: any) => buildProjectListNode(project.name, openProject))
const projectsList = projectsListResult.result.projects.map((project: any) =>
buildProjectListNode(project.name, openProject)
)
projectsList.forEach((element: any) => {
projectsListNode.insertBefore(element, newProjectNode)
@ -139,7 +134,10 @@ async function loadProjectsList(openProject: (project: string) => void): Promise
* @param projectName the name of the project
* @param openProject the callback that opens IDE with the provided project
*/
function buildProjectListNode(projectName: string, openProject: (project: string) => void): HTMLLIElement {
function buildProjectListNode(
projectName: string,
openProject: (project: string) => void
): HTMLLIElement {
const li = document.createElement('li')
li.setAttribute('style', 'cursor: pointer;')
li.onclick = () => {
@ -176,7 +174,10 @@ function setTemplateCardHandlers(openProject: (project: String) => void): void {
* @param element the HTML element of the template card
* @param openProject the callback that opens IDE with the provided project
*/
function setTemplateCardHandler(element: HTMLElement, openProject: (project: string) => void): void {
function setTemplateCardHandler(
element: HTMLElement,
openProject: (project: string) => void
): void {
element.setAttribute('style', 'cursor: pointer;')
element.onclick = () => {
const projectName = getProjectName(element.id)
@ -186,7 +187,7 @@ function setTemplateCardHandler(element: HTMLElement, openProject: (project: str
PM.createProject(projectName, templateName)
.then((response: any) => {
if (response.error !== undefined) {
console.error("Project manager createProject failed", response)
console.error('Project manager createProject failed', response)
displayStatusBox(response.error.message)
} else {
restoreRootHtml()
@ -195,7 +196,7 @@ function setTemplateCardHandler(element: HTMLElement, openProject: (project: str
})
.catch((error: any) => {
console.error('onclick', element.id, error)
displayStatusBox("Failed to open a template.")
displayStatusBox('Failed to open a template.')
})
}
}

View File

@ -1,4 +1,4 @@
import * as wasm_rust_glue from "wasm_rust_glue"
import * as wasm_rust_glue from 'wasm_rust_glue'
/// WARNING
/// This module is a hacky binding to wasm_pack. It works only if the wasm_pack output is

View File

@ -1,13 +1,13 @@
let config = {
name: "enso-studio-icons",
version: "1.0.0",
name: 'enso-studio-icons',
version: '1.0.0',
scripts: {
"build": "node src/index.js"
build: 'node src/index.js',
},
devDependencies: {
"sharp": "^0.26.2",
"to-ico": "^1.1.5"
}
sharp: '^0.26.2',
'to-ico': '^1.1.5',
},
}
module.exports = { config }

View File

@ -23,19 +23,29 @@ class Logo {
this.d = 4
let innerSize = 56
this.scale1 = innerSize / 64
this.scale = (this.xsize / 64)
this.scale = this.xsize / 64
this.tx = (64 - innerSize) / 2
if (this.compatibleMode) { this.ref = "xlink:href" } else { this.ref = "href" }
if (this.compatibleMode) {
this.ref = 'xlink:href'
} else {
this.ref = 'href'
}
this.defs = ''
}
generate() {
return `
<svg version="1.1" baseProfile="full" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" height="${this.xsize}" width="${this.xsize}" viewBox="0 0 ${this.xsize} ${this.xsize}">
<svg version="1.1" baseProfile="full" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" height="${
this.xsize
}" width="${this.xsize}" viewBox="0 0 ${this.xsize} ${this.xsize}">
<defs>
<circle id="innerCircle" cx="32" cy="32" r="${this.innerRadius}"/>
<circle id="leftAtom" cx="${this.borderWidth + this.borderOffset + this.atomRadius + this.atomDiff - this.d}" cy="32" r="${this.atomRadius + this.atomDiff + this.d}"/>
<circle id="rightAtom" cx="${this.borderWidth + this.borderOffset + 3 * this.atomRadius + this.atomDiff}" cy="32" r="${this.atomRadius - this.atomDiff}"/>
<circle id="leftAtom" cx="${
this.borderWidth + this.borderOffset + this.atomRadius + this.atomDiff - this.d
}" cy="32" r="${this.atomRadius + this.atomDiff + this.d}"/>
<circle id="rightAtom" cx="${
this.borderWidth + this.borderOffset + 3 * this.atomRadius + this.atomDiff
}" cy="32" r="${this.atomRadius - this.atomDiff}"/>
<mask id="innerCircleMask">
<use ${this.ref}="#innerCircle" fill="white"/>
</mask>
@ -101,17 +111,19 @@ class AppLogo extends Logo {
}
}
fastGenerate = (cons) => (...args) => new cons(...args).generate()
fastGenerate =
cons =>
(...args) =>
new cons(...args).generate()
exports.generateMinimalWhiteLogo = fastGenerate(AppLogo)
const fss = require('fs')
const fs = fss.promises
const exec = require('child_process').exec
const spawn = require('child_process').spawn
const toIco = require('to-ico')
const sharp = require("sharp")
const sharp = require('sharp')
const path = require('path')
const thisPath = path.resolve(__dirname)
@ -119,7 +131,6 @@ const root = path.resolve(thisPath,'..','..','..','..','..')
const distPath = path.resolve(root, 'dist', 'icons')
const donePath = path.resolve(distPath, 'init')
async function genIcons() {
let sizes = [16, 32, 64, 128, 256, 512, 1024]
let win_sizes = [16, 32, 64, 128, 256]
@ -129,7 +140,7 @@ async function genIcons() {
return
}
console.log("Generating SVG icons.")
console.log('Generating SVG icons.')
await fs.mkdir(path.resolve(distPath, 'svg'), { recursive: true })
await fs.mkdir(path.resolve(distPath, 'png'), { recursive: true })
for (let size of sizes) {
@ -141,38 +152,46 @@ async function genIcons() {
/// AND KEEPS THE METADATA INFORMATION ABOUT DPI OF 144.
/// It is required to properly display png images on MacOS.
/// There is currently no other way in `sharp` to do it.
console.log("Generating PNG icons.")
console.log('Generating PNG icons.')
for (let size of sizes) {
let inName = `icon_${size}x${size}.svg`
let outName = `icon_${size}x${size}.png`
await sharp(`${distPath}/svg/${inName}`,{density:144}).png().resize({
await sharp(`${distPath}/svg/${inName}`, { density: 144 })
.png()
.resize({
width: size,
kernel : sharp.kernel.mitchell
}).toFile(`${distPath}/png/${outName}`)
kernel: sharp.kernel.mitchell,
})
.toFile(`${distPath}/png/${outName}`)
}
for (let size of sizes.slice(1)) {
let size2 = size / 2
let inName = `icon_${size}x${size}.svg`
let outName = `icon_${size2}x${size2}@2x.png`
await sharp(`${distPath}/svg/${inName}`,{density:144}).png().resize({
await sharp(`${distPath}/svg/${inName}`, { density: 144 })
.png()
.resize({
width: size,
kernel : sharp.kernel.mitchell
}).toFile(`${distPath}/png/${outName}`)
kernel: sharp.kernel.mitchell,
})
.toFile(`${distPath}/png/${outName}`)
}
console.log("Generating ICNS.")
console.log('Generating ICNS.')
exec(`cp -R ${distPath}/png ${distPath}/png.iconset`)
exec(`iconutil --convert icns --output ${distPath}/icon.icns ${distPath}/png.iconset`)
console.log("Generating ICO.")
console.log('Generating ICO.')
let files = []
for (let size of win_sizes) {
let inName = `icon_${size}x${size}.png`
let data = await fs.readFile(`${distPath}/png/${inName}`)
files.push(data)
}
toIco(files).then(buf => { fss.writeFileSync(`${distPath}/icon.ico`, buf) })
toIco(files).then(buf => {
fss.writeFileSync(`${distPath}/icon.ico`, buf)
})
let handle = await fs.open(donePath, 'w')
await handle.close()

View File

@ -29,4 +29,3 @@
"mock-fs": "^4.13.0"
}
}

View File

@ -9,18 +9,14 @@ const yargs = require('yargs')
const defaultPort = require('../../config.js').defaultLogServerPort
module.exports = {
startServer
startServer,
}
function main(argv) {
startServer(parse_args(argv).port)
}
// =================
// === Constants ===
// =================
@ -32,8 +28,6 @@ const httpStatusCodes = {
internalServerError: 500,
}
// ========================
// === Argument Parsing ===
// ========================
@ -46,15 +40,12 @@ function parse_args(argv) {
'The number of the port that this server will listen on. ' +
'If the the number is 0 then an arbitrary free port will be chosen.',
type: 'number',
default: defaultPort
default: defaultPort,
})
.help()
.alias('help', 'h')
.argv
.alias('help', 'h').argv
}
// ==============
// === Server ===
// ==============
@ -63,9 +54,11 @@ function startServer(port) {
const app = express()
app.use(express.text())
app.post("/", async (req, res) => {
if (typeof req.headers.origin === 'undefined' ||
(new URL(req.headers.origin).hostname) !== 'localhost') {
app.post('/', async (req, res) => {
if (
typeof req.headers.origin === 'undefined' ||
new URL(req.headers.origin).hostname !== 'localhost'
) {
res.sendStatus(httpStatusCodes.forbidden)
} else if (typeof req.body !== 'string') {
res.sendStatus(httpStatusCodes.badRequest)
@ -75,9 +68,7 @@ function startServer(port) {
console.log(`Saved log from origin ${req.headers.origin}`)
res.sendStatus(httpStatusCodes.noContent)
} catch (e) {
console.error(
'Could not write log file:\n' +
e.message)
console.error('Could not write log file:\n' + e.message)
res.sendStatus(httpStatusCodes.internalServerError)
}
}
@ -90,8 +81,6 @@ function startServer(port) {
return server
}
// ==================
// === File Utils ===
// ==================
@ -107,7 +96,6 @@ async function writeLog(message) {
await fs.promises.writeFile(`${dir}/${file}`, message)
}
/**
* Returns the current UTC date and time in the format "yyy-MM-dd_HH:mm:ss.".
*/
@ -115,19 +103,16 @@ function timestamp() {
const d = new Date()
const year = d.getUTCFullYear().toString()
const month = d.getUTCMonth().toString().padStart(2, "0")
const day = d.getUTCDate().toString().padStart(2, "0")
const month = d.getUTCMonth().toString().padStart(2, '0')
const day = d.getUTCDate().toString().padStart(2, '0')
const hour = d.getUTCHours().toString().padStart(2, "0")
const minute = d.getUTCMinutes().toString().padStart(2, "0")
const second = d.getUTCSeconds().toString().padStart(2, "0")
const hour = d.getUTCHours().toString().padStart(2, '0')
const minute = d.getUTCMinutes().toString().padStart(2, '0')
const second = d.getUTCSeconds().toString().padStart(2, '0')
return `${year}-${month}-${day}_${hour}:${minute}:${second}`
}
if (require.main === module) {
const command_line_args = process.argv.slice(2)
main(command_line_args)

View File

@ -6,11 +6,7 @@ const path = require('path')
const { startServer } = require('../server')
describe('Logging Server', function () {
let server
let serverUrl
@ -18,20 +14,20 @@ describe('Logging Server', function () {
const goodConfig = {
headers: {
'Content-Type': 'text/plain',
'Origin': 'http://localhost/'
}
Origin: 'http://localhost/',
},
}
const wrongOriginConfig = {
headers: {
'Content-Type': 'text/plain',
'Origin': 'http://attacker/'
}
Origin: 'http://attacker/',
},
}
const wrongContentTypeConfig = {
headers: {
'Content-Type': 'image/jpeg',
'Origin': 'http://localhost/'
}
Origin: 'http://localhost/',
},
}
beforeEach(function (done) {
@ -41,7 +37,7 @@ describe('Logging Server', function () {
// We mock the file system so the server does not actually write logs to disk.
mockFs({
[rawBodyDir]: mockFs.load(rawBodyDir)
[rawBodyDir]: mockFs.load(rawBodyDir),
})
const port = 0 // Choose an arbitrary available port
@ -74,12 +70,11 @@ describe('Logging Server', function () {
await Promise.allSettled([
axios.post(serverUrl, '', goodConfig),
axios.post(serverUrl, '', wrongOriginConfig),
axios.post(serverUrl, '', wrongContentTypeConfig)
axios.post(serverUrl, '', wrongContentTypeConfig),
])
await axios.post(serverUrl, dummyMessage, goodConfig)
const log_files = fs.readdirSync('log/')
assert(log_files.some(file =>
fs.readFileSync(`log/${file}`).toString() === dummyMessage))
assert(log_files.some(file => fs.readFileSync(`log/${file}`).toString() === dummyMessage))
})
})

View File

@ -1,6 +1,6 @@
let config = {
name: 'enso-studio-project-manager',
version: "1.0.0",
version: '1.0.0',
scripts: {
build: 'npx ts-node src/build.ts',
},

View File

@ -39,7 +39,10 @@ async function get_build_config() {
// === Project Manager ===
// =======================
interface BuildInfo { version: string, target: string }
interface BuildInfo {
version: string
target: string
}
function get_project_manager_url({ version, target }: BuildInfo): string {
console.log('webpack target ' + target)
@ -145,7 +148,8 @@ async function download_project_manager(file_url: string, overwrite: boolean): P
const target_file = fss.createWriteStream(file_path)
const progress_indicator = new DownloadProgressIndicator()
await new Promise((resolve, reject) =>
http.get(options, (res: IncomingMessage) => {
http
.get(options, (res: IncomingMessage) => {
res.on('data', (data: string) => {
target_file.write(data)
progress_indicator.add_progress_bytes(data.length)
@ -154,7 +158,8 @@ async function download_project_manager(file_url: string, overwrite: boolean): P
console.log(`${file_url} downloaded to "${file_path}".`)
resolve(undefined)
})
}).on('error', async (e: http.ClientRequest) => {
})
.on('error', async (e: http.ClientRequest) => {
target_file.end()
await fs.rm(file_path)
reject('Error: The download of the project manager was interrupted:\n' + e)
@ -193,9 +198,10 @@ async function main() {
process.exit(1)
}
}
if (buildInfo.version !== existing_build_info?.version ||
buildInfo.target !== existing_build_info?.target) {
if (
buildInfo.version !== existing_build_info?.version ||
buildInfo.target !== existing_build_info?.target
) {
// We remove the build info file to avoid misinformation if the build is interrupted during
// the call to `download_project_manager`.
// We use `force: true` because the file might not exist.

View File

@ -2,8 +2,7 @@
/// which scans the GLSL code and mangles all names of primitive functions. This way we can define
/// overloaded functions the same way as we did in GLSL 100.
let builtins =
`float radians(float degrees)
let builtins = `float radians(float degrees)
vec2 radians(vec2 degrees)
vec3 radians(vec3 degrees)
vec4 radians(vec4 degrees)
@ -223,8 +222,9 @@ function redirect_builtins() {
let argsStr = match[3]
let args = argsStr.split(', ').map(v => v.split(' '))
let argNames = args.map(a => a[1])
let redirection =
`${outType} overloaded_${fname} (${argsStr}) {return ${fname}(${argNames.join(',')});}`
let redirection = `${outType} overloaded_${fname} (${argsStr}) {return ${fname}(${argNames.join(
','
)});}`
names.push(fname)
redirections.push(redirection)
}

View File

@ -13,7 +13,6 @@ export class TextInputHandlers {
this.text_area.focus()
this.bind_text_area_events()
this.bind_window_events()
}
// Set event handler. The name can be 'keyup' or 'keydown'.
@ -46,11 +45,15 @@ export class TextInputHandlers {
bind_text_area_events() {
this.text_area.addEventListener('cut', e => {
// Clear textarea in next frame (after cutting).
setTimeout(_ => {this.text_area.value = "";}, 0)
setTimeout(_ => {
this.text_area.value = ''
}, 0)
})
this.text_area.addEventListener('copy', e => {
// Clear textarea in next frame (after copying).
setTimeout(_ => {this.text_area.value = "";}, 0)
setTimeout(_ => {
this.text_area.value = ''
}, 0)
})
this.text_area.addEventListener('paste', e => {
if (typeof this.paste_handler !== 'undefined') {
@ -67,7 +70,7 @@ export class TextInputHandlers {
this.text_area.focus()
})
this.text_area.addEventListener('keydown', e => {
let code = e.keyCode;
let code = e.keyCode
let is_cut = code === 88 && (e.metaKey || e.ctrlKey)
let is_copy = code === 67 && (e.metaKey || e.ctrlKey)
@ -75,8 +78,8 @@ export class TextInputHandlers {
if (is_copy || is_cut) {
if (typeof this.copy_handler !== 'undefined') {
this.text_area.value = this.copy_handler(is_cut)
this.text_area.selectionStart = 0;
this.text_area.selectionEnd = this.text_area.value.length;
this.text_area.selectionStart = 0
this.text_area.selectionEnd = this.text_area.value.length
} else {
e.preventDefault()
}
@ -107,7 +110,7 @@ export class TextInputHandlers {
// Creates invisible textarea.
function create_invisible_text_area() {
const css_class_name = "enso";
const css_class_name = 'enso'
let text_area = document.createElement('textarea')
text_area.className = css_class_name

View File

@ -1,8 +1,5 @@
{
"goog:chromeOptions": {
"args": [
"--no-proxy-server",
"--no-sandbox"
]
"args": ["--no-proxy-server", "--no-sandbox"]
}
}

View File

@ -25,10 +25,13 @@
}
@keyframes sk-bouncedelay {
0%, 80%, 100% {
0%,
80%,
100% {
transform: scale(0);
} 40% {
transform: scale(1.0);
}
40% {
transform: scale(1);
}
}
</style>

View File

@ -6,7 +6,7 @@
function fallbackWriteText(text) {
let successful = false
let textArea = document.createElement("textarea")
let textArea = document.createElement('textarea')
// *** This styling is an extra step which is likely not required. ***
//
@ -44,14 +44,15 @@ function fallbackWriteText(text) {
textArea.style.background = 'transparent'
textArea.value = text
textArea.style.top = "0"
textArea.style.left = "0"
textArea.style.position = "fixed"
textArea.style.top = '0'
textArea.style.left = '0'
textArea.style.position = 'fixed'
document.body.appendChild(textArea)
textArea.focus()
textArea.select()
try { successful = document.execCommand('copy') == 1 }
catch (err) {}
try {
successful = document.execCommand('copy') == 1
} catch (err) {}
document.body.removeChild(textArea)
if (!successful) {
console.error('Could not write to clipboard.')
@ -62,18 +63,21 @@ export function writeText(text) {
if (!navigator.clipboard) {
fallbackWriteText(text)
} else {
navigator.clipboard.writeText(text).then(() => {}, (err) => {
navigator.clipboard.writeText(text).then(
() => {},
err => {
fallbackWriteText(text)
})
}
)
}
}
/// Firefox only supports reading the clipboard in browser extensions, so it will
/// only work with `cmd + v` shortcut. To learn more, see the
/// [MSDN compatibility note](https://developer.mozilla.org/en-US/docs/Web/API/Clipboard/readText).
let lastPaste = ""
let lastPaste = ''
function init_firefox_fallback() {
window.addEventListener('paste', (event) => {
window.addEventListener('paste', event => {
lastPaste = (event.clipboardData || window.clipboardData).getData('text')
})
}
@ -82,16 +86,17 @@ export function readText(callback) {
if (!navigator.clipboard) {
callback(lastPaste)
} else {
navigator.clipboard.readText().then(function(text) {
navigator.clipboard.readText().then(
function (text) {
callback(text)
}, function(err) {
},
function (err) {
callback(lastPaste)
})
}
)
}
}
// ======================
// === Initialization ===
// ======================

View File

@ -32,7 +32,6 @@ class IxPool {
}
}
// ============
// === Pool ===
// ============
@ -40,7 +39,7 @@ class IxPool {
class Pool {
constructor(cons) {
this.cons = cons
this.ixs = new IxPool
this.ixs = new IxPool()
}
reserve(...args) {
@ -55,13 +54,11 @@ class Pool {
}
}
// ============================
// === IntersectionObserver ===
// ============================
let intersectionObserverPool =
new Pool((...args) => new IntersectionObserver(...args))
let intersectionObserverPool = new Pool((...args) => new IntersectionObserver(...args))
export function intersection_observe(target, f) {
let id = intersectionObserverPool.reserve(intersection_observer_update(f))
@ -76,7 +73,7 @@ export function intersection_unobserve(id) {
function intersection_observer_update(f) {
return entries => {
let rect = entries[0].boundingClientRect;
f(rect.x, rect.y, rect.width, rect.height);
let rect = entries[0].boundingClientRect
f(rect.x, rect.y, rect.width, rect.height)
}
}

View File

@ -24,7 +24,6 @@ class IxPool {
}
}
// ============
// === Pool ===
// ============
@ -32,7 +31,7 @@ class IxPool {
class Pool {
constructor(cons) {
this.cons = cons
this.ixs = new IxPool
this.ixs = new IxPool()
}
reserve(...args) {
@ -47,7 +46,6 @@ class Pool {
}
}
// ======================
// === ResizeObserver ===
// ======================
@ -67,7 +65,7 @@ export function resize_unobserve(id) {
function resize_observer_update(f) {
return entries => {
let rect = entries[0].contentRect;
f(rect.width, rect.height);
let rect = entries[0].contentRect
f(rect.width, rect.height)
}
}