diff --git a/src/mol-plugin-ui/controls/parameters.tsx b/src/mol-plugin-ui/controls/parameters.tsx index ac908aeccc687e434a9a4bd1306082b156633f19..9bce0e69e7b3fd4bdf9d43fde760588dba81de6f 100644 --- a/src/mol-plugin-ui/controls/parameters.tsx +++ b/src/mol-plugin-ui/controls/parameters.tsx @@ -7,6 +7,7 @@ import * as React from 'react'; import { Mat4, Vec2, Vec3 } from '../../mol-math/linear-algebra'; +import { Script } from '../../mol-script/script'; import { Asset } from '../../mol-util/assets'; import { Color } from '../../mol-util/color'; import { ColorListEntry } from '../../mol-util/color/color'; @@ -1466,31 +1467,35 @@ export class ConvertedControl extends React.PureComponent<ParamProps<PD.Converte } } -export class ScriptControl extends SimpleParam<PD.Script> { - onChange = (e: React.ChangeEvent<HTMLInputElement>) => { - const value = e.target.value; - if (value !== this.props.value.expression) { - this.update({ language: this.props.value.language, expression: value }); +export class ScriptControl extends React.PureComponent<ParamProps<PD.Script>> { + onChange: ParamOnChange = ({ name, value }) => { + const k = name as 'language' | 'expression'; + if (value !== this.props.value[k]) { + this.props.onChange({ param: this.props.param, name: this.props.name, value: { ...this.props.value, [k]: value } }); } }; - onKeyPress = (e: React.KeyboardEvent<HTMLInputElement>) => { - if ((e.keyCode === 13 || e.charCode === 13 || e.key === 'Enter')) { - if (this.props.onEnter) this.props.onEnter(); - } - e.stopPropagation(); - }; - - renderControl() { + render() { // TODO: improve! - const placeholder = this.props.param.label || camelCaseToWords(this.props.name); - return <input type='text' - value={this.props.value.expression || ''} - placeholder={placeholder} - onChange={this.onChange} - onKeyPress={this.props.onEnter ? this.onKeyPress : void 0} - disabled={this.props.isDisabled} - />; + const selectParam: PD.Select<PD.Script['defaultValue']['language']> = { + defaultValue: this.props.value.language, + options: PD.objectToOptions(Script.Info), + type: 'select', + }; + const select = <SelectControl param={selectParam} + isDisabled={this.props.isDisabled} onChange={this.onChange} onEnter={this.props.onEnter} + name='language' value={this.props.value.language} />; + + const textParam: PD.Text = { + defaultValue: this.props.value.language, + type: 'text', + }; + const text = <TextControl param={textParam} isDisabled={this.props.isDisabled} onChange={this.onChange} name='expression' value={this.props.value.expression} />; + + return <> + {select} + {text} + </>; } } \ No newline at end of file diff --git a/src/mol-script/script.ts b/src/mol-script/script.ts index 553e5e2425ce417962cf2b29b60d1daec4c43e7f..bfc55f7f3f40a7959edccf677d4a92db558b441b 100644 --- a/src/mol-script/script.ts +++ b/src/mol-script/script.ts @@ -11,15 +11,7 @@ import { Expression } from './language/expression'; import { StructureElement, QueryContext, StructureSelection, Structure, QueryFn, QueryContextOptions } from '../mol-model/structure'; import { compile } from './runtime/query/compiler'; import { MolScriptBuilder } from './language/builder'; - - - - - - - - - +import { assertUnreachable } from '../mol-util/type-helpers'; export { Script }; @@ -30,7 +22,14 @@ function Script(expression: string = '(sel.atom.all)', language: Script.Language } namespace Script { - export type Language = 'mol-script' | 'pymol' | 'vmd' | 'jmol' | 'rasmol' + export const Info = { + 'mol-script': 'Mol-Script', + 'pymol': 'PyMOL', + 'vmd': 'VMD', + 'jmol': 'Jmol', + 'rasmol': 'Rasmol' + }; + export type Language = keyof typeof Info; export function is(x: any): x is Script { return !!x && typeof (x as Script).expression === 'string' && !!(x as Script).language; @@ -43,20 +42,17 @@ namespace Script { export function toExpression(script: Script): Expression { switch (script.language) { case 'mol-script': - const parsed = parseMolScript(script.expression); - if (parsed.length === 0) throw new Error('No query'); - return transpileMolScript(parsed[0]); + const parsed = parseMolScript(script.expression); + if (parsed.length === 0) throw new Error('No query'); + return transpileMolScript(parsed[0]); case 'pymol': - return parse('pymol', script.expression) as Expression; case 'jmol': - return parse('jmol', script.expression) as Expression; case 'vmd': - return parse('vmd', script.expression) as Expression; case 'rasmol': - return parse('rasmol', script.expression) as Expression; + return parse(script.language, script.expression); + default: + assertUnreachable(script.language); } - - throw new Error('unsupported script language'); } export function toQuery(script: Script): QueryFn<StructureSelection> { diff --git a/src/mol-script/transpile.ts b/src/mol-script/transpile.ts index cf6c345177257ec3f6a87354c024dcc9aecefb6a..8f185a1e1c44f400621c4b3ca30f2e6910a52d7e 100644 --- a/src/mol-script/transpile.ts +++ b/src/mol-script/transpile.ts @@ -1,5 +1,5 @@ /** - * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info. + * Copyright (c) 2022 mol* contributors, licensed under MIT, See LICENSE file for more info. * * @author Koya Sakuma */ @@ -9,9 +9,11 @@ import { Transpiler } from './transpilers/transpiler'; import { _transpiler } from './transpilers/all'; +import { Expression } from './language/expression'; +import { Script } from './script'; const transpiler: {[index: string]: Transpiler} = _transpiler; -export function parse(lang: string, str: string) { +export function parse(lang: Script.Language, str: string): Expression { try { const query = transpiler[lang](str); @@ -25,5 +27,6 @@ export function parse(lang: string, str: string) { console.log(str); console.log(e.message); console.log('\n'); + throw e; } }