1 /* 2 * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package jdk.nashorn.tools.jjs; 27 28 import java.util.Collections; 29 import java.util.HashSet; 30 import java.util.Set; 31 import java.util.function.Consumer; 32 import java.util.ServiceLoader; 33 import jdk.nashorn.api.scripting.AbstractJSObject; 34 import jdk.internal.editor.spi.BuildInEditorProvider; 35 import jdk.nashorn.internal.runtime.JSType; 36 import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED; 37 38 /* 39 * "edit" top level script function which shows an external Window 40 * for editing and evaluating scripts from it. 41 */ 42 final class EditObject extends AbstractJSObject { 43 private static final Set<String> props; 44 static { 45 final HashSet<String> s = new HashSet<>(); 46 s.add("editor"); 47 props = Collections.unmodifiableSet(s); 48 } 49 50 private final Console console; 51 private final Consumer<String> errorHandler; 52 private final Consumer<String> evaluator; 53 private String editor; 54 55 EditObject(final Console console, final Consumer<String> errorHandler, 56 final Consumer<String> evaluator) { 57 this.console = console; 58 this.errorHandler = errorHandler; 59 this.evaluator = evaluator; 60 } 61 62 @Override 63 public Object getDefaultValue(final Class<?> hint) { 64 if (hint == String.class) { 65 return toString(); 66 } 67 return UNDEFINED; 68 } 69 70 @Override 71 public String toString() { 72 return "function edit() { [native code] }"; 73 } 74 75 @Override 76 public Set<String> keySet() { 77 return props; 78 } 79 80 @Override 81 public Object getMember(final String name) { 82 if (name.equals("editor")) { 83 return editor; 84 } 85 return UNDEFINED; 86 } 87 88 @Override 89 public void setMember(final String name, final Object value) { 90 if (name.equals("editor")) { 91 this.editor = value != null && value != UNDEFINED? JSType.toString(value) : ""; 92 } 93 } 94 95 // called whenever user 'saves' script in editor 96 class SaveHandler implements Consumer<String> { 97 private String lastStr; // last seen code 98 99 SaveHandler(final String str) { 100 this.lastStr = str; 101 } 102 103 @Override 104 public void accept(final String str) { 105 // ignore repeated save of the same code! 106 if (! str.equals(lastStr)) { 107 this.lastStr = str; 108 // evaluate the new code 109 evaluator.accept(str); 110 } 111 } 112 } 113 114 @Override 115 public Object call(final Object thiz, final Object... args) { 116 final String initText = args.length > 0? JSType.toString(args[0]) : ""; 117 final SaveHandler saveHandler = new SaveHandler(initText); 118 if (editor != null && !editor.isEmpty()) { 119 ExternalEditor.edit(editor, errorHandler, initText, saveHandler, console); 120 } else if (! Main.HEADLESS) { 121 try { 122 ServiceLoader<BuildInEditorProvider> sl 123 = ServiceLoader.load(BuildInEditorProvider.class); 124 //find the highest ranking provider 125 BuildInEditorProvider provider = null; 126 for (BuildInEditorProvider p : sl){ 127 if (provider == null || p.rank() > provider.rank()) { 128 provider = p; 129 } 130 } 131 if (provider != null) { 132 provider.edit(null, initText, saveHandler, errorHandler); 133 } else { 134 errorHandler.accept(Main.getMessage("jjs.err.no.builtin.editor")); 135 } 136 } catch (RuntimeException ex) { 137 errorHandler.accept(Main.getMessage("jjs.err.cant.launch.editor")); 138 } 139 } else { 140 errorHandler.accept(Main.getMessage("no.editor")); 141 } 142 return UNDEFINED; 143 } 144 145 @Override 146 public boolean isFunction() { 147 return true; 148 } 149 }