opt(ui): js beautifier supports formatting xml
This commit is contained in:
@@ -88,6 +88,14 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
(function() {
|
(function() {
|
||||||
|
var formatXml = require("xml_formatter");
|
||||||
|
function println(str){
|
||||||
|
java.lang.System.out.println(str);
|
||||||
|
}
|
||||||
|
String.prototype.replaceAll = function(search, replacement) {
|
||||||
|
var target = this;
|
||||||
|
return target.split(search).join(replacement);
|
||||||
|
};
|
||||||
var legacy_beautify_js =
|
var legacy_beautify_js =
|
||||||
/******/ (function(modules) { // webpackBootstrap
|
/******/ (function(modules) { // webpackBootstrap
|
||||||
/******/ // The module cache
|
/******/ // The module cache
|
||||||
@@ -363,6 +371,7 @@ function Beautifier(js_source_text, options) {
|
|||||||
'TK_WORD': handle_word,
|
'TK_WORD': handle_word,
|
||||||
'TK_RESERVED': handle_word,
|
'TK_RESERVED': handle_word,
|
||||||
'TK_SEMICOLON': handle_semicolon,
|
'TK_SEMICOLON': handle_semicolon,
|
||||||
|
'TK_XML': handle_string,
|
||||||
'TK_STRING': handle_string,
|
'TK_STRING': handle_string,
|
||||||
'TK_EQUALS': handle_equals,
|
'TK_EQUALS': handle_equals,
|
||||||
'TK_OPERATOR': handle_operator,
|
'TK_OPERATOR': handle_operator,
|
||||||
@@ -696,6 +705,13 @@ function Beautifier(js_source_text, options) {
|
|||||||
|
|
||||||
printable_token = printable_token || current_token.text;
|
printable_token = printable_token || current_token.text;
|
||||||
print_token_line_indentation();
|
print_token_line_indentation();
|
||||||
|
if(current_token.type == "TK_XML" && printable_token){
|
||||||
|
var indent_count = output.current_line._indent_count;
|
||||||
|
println("indent_count: " + indent_count);
|
||||||
|
var indent = output.indent_cache[Math.max(0, indent_count - 1)];
|
||||||
|
printable_token = formatXml(printable_token, {margin: indent});
|
||||||
|
current_token.text = printable_token;
|
||||||
|
}
|
||||||
output.add_token(printable_token);
|
output.add_token(printable_token);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1877,14 +1893,14 @@ module.exports.mergeOpts = mergeOpts;
|
|||||||
function OutputLine(parent) {
|
function OutputLine(parent) {
|
||||||
var _character_count = 0;
|
var _character_count = 0;
|
||||||
// use indent_count as a marker for lines that have preserved indentation
|
// use indent_count as a marker for lines that have preserved indentation
|
||||||
var _indent_count = -1;
|
this._indent_count = -1;
|
||||||
|
|
||||||
var _items = [];
|
var _items = [];
|
||||||
var _empty = true;
|
var _empty = true;
|
||||||
|
|
||||||
this.set_indent = function(level) {
|
this.set_indent = function(level) {
|
||||||
_character_count = parent.baseIndentLength + level * parent.indent_length;
|
_character_count = parent.baseIndentLength + level * parent.indent_length;
|
||||||
_indent_count = level;
|
this._indent_count = level;
|
||||||
};
|
};
|
||||||
|
|
||||||
this.get_character_count = function() {
|
this.get_character_count = function() {
|
||||||
@@ -1920,8 +1936,8 @@ function OutputLine(parent) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
this.remove_indent = function() {
|
this.remove_indent = function() {
|
||||||
if (_indent_count > 0) {
|
if (this._indent_count > 0) {
|
||||||
_indent_count -= 1;
|
this._indent_count -= 1;
|
||||||
_character_count -= parent.indent_length;
|
_character_count -= parent.indent_length;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -1937,8 +1953,8 @@ function OutputLine(parent) {
|
|||||||
this.toString = function() {
|
this.toString = function() {
|
||||||
var result = '';
|
var result = '';
|
||||||
if (!this._empty) {
|
if (!this._empty) {
|
||||||
if (_indent_count >= 0) {
|
if (this._indent_count >= 0) {
|
||||||
result = parent.indent_cache[_indent_count];
|
result = parent.indent_cache[this._indent_count];
|
||||||
}
|
}
|
||||||
result += _items.join('');
|
result += _items.join('');
|
||||||
}
|
}
|
||||||
@@ -2567,7 +2583,8 @@ function Tokenizer(input_string, opts) {
|
|||||||
xmlStr += input.match(/[\s\S]*/g)[0];
|
xmlStr += input.match(/[\s\S]*/g)[0];
|
||||||
}
|
}
|
||||||
xmlStr = xmlStr.replace(acorn.allLineBreaks, '\n');
|
xmlStr = xmlStr.replace(acorn.allLineBreaks, '\n');
|
||||||
return [xmlStr, "TK_STRING"];
|
n_newlines = 1;
|
||||||
|
return [xmlStr, "TK_XML"];
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
//
|
//
|
||||||
43
app/src/main/assets/js/js-beautify/xml_formatter.js
Normal file
43
app/src/main/assets/js/js-beautify/xml_formatter.js
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
|
||||||
|
const stringTimesN = (n, char) => Array(n + 1).join(char)
|
||||||
|
|
||||||
|
// Adapted from https://gist.github.com/sente/1083506
|
||||||
|
function prettifyXml(xmlInput, options) {
|
||||||
|
options = options || {};
|
||||||
|
let newlineOption = options.newline || '\n';
|
||||||
|
let indentOption = options.indent || 4;
|
||||||
|
let margin = options.margin || '';
|
||||||
|
const indentString = stringTimesN(indentOption, ' ')
|
||||||
|
|
||||||
|
let formatted = '';
|
||||||
|
const regex = /(>)(<)(\/*)/g;
|
||||||
|
const xml = xmlInput.replace(regex, '$1' + newlineOption + '$2$3');
|
||||||
|
let pad = 0;
|
||||||
|
xml.split(/\r?\n/).forEach(l => {
|
||||||
|
const line = l.trim();
|
||||||
|
|
||||||
|
let indent = 0;
|
||||||
|
if (line.match(/.+<\/\w[^>]*>$/)) {
|
||||||
|
indent = 0;
|
||||||
|
} else if (line.match(/^<\/\w/)) {
|
||||||
|
// Somehow istanbul doesn't see the else case as covered, although it is. Skip it.
|
||||||
|
/* istanbul ignore else */
|
||||||
|
if (pad !== 0) {
|
||||||
|
pad -= 1
|
||||||
|
}
|
||||||
|
} else if (line.match(/^<\w([^>]*[^\/])?>.*$/)) {
|
||||||
|
indent = 1
|
||||||
|
} else {
|
||||||
|
indent = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
const padding = stringTimesN(pad, indentString);
|
||||||
|
formatted += margin + padding + line + newlineOption // eslint-disable-line prefer-template
|
||||||
|
pad += indent
|
||||||
|
})
|
||||||
|
|
||||||
|
return formatted.trim()
|
||||||
|
}
|
||||||
|
|
||||||
|
// For non-es2015 usage
|
||||||
|
module.exports = prettifyXml
|
||||||
@@ -211,6 +211,9 @@ public class EditorView extends FrameLayout implements CodeCompletionBar.OnHintC
|
|||||||
if (content != null) {
|
if (content != null) {
|
||||||
setInitialText(content);
|
setInitialText(content);
|
||||||
} else {
|
} else {
|
||||||
|
if (path == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
mFile = new File(path);
|
mFile = new File(path);
|
||||||
if (mName == null) {
|
if (mName == null) {
|
||||||
mName = mFile.getName();
|
mName = mFile.getName();
|
||||||
|
|||||||
@@ -80,7 +80,7 @@ public class CodeEditor extends HVScrollView {
|
|||||||
mTextViewRedoUndo = new TextViewUndoRedo(mCodeEditText);
|
mTextViewRedoUndo = new TextViewUndoRedo(mCodeEditText);
|
||||||
mJavaScriptHighlighter = new JavaScriptHighlighter(mTheme, mCodeEditText);
|
mJavaScriptHighlighter = new JavaScriptHighlighter(mTheme, mCodeEditText);
|
||||||
setTheme(Theme.getDefault(getContext()));
|
setTheme(Theme.getDefault(getContext()));
|
||||||
mJsBeautifier = new JsBeautifier(this, "js/beautify.js");
|
mJsBeautifier = new JsBeautifier(this, "js/js-beautify");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package com.stardust.autojs.engine;
|
package com.stardust.autojs.engine;
|
||||||
|
|
||||||
|
import android.content.res.AssetManager;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
|
|
||||||
import org.mozilla.javascript.Scriptable;
|
import org.mozilla.javascript.Scriptable;
|
||||||
@@ -7,6 +8,7 @@ import org.mozilla.javascript.commonjs.module.provider.ModuleSource;
|
|||||||
import org.mozilla.javascript.commonjs.module.provider.UrlModuleSourceProvider;
|
import org.mozilla.javascript.commonjs.module.provider.UrlModuleSourceProvider;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStreamReader;
|
import java.io.InputStreamReader;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
@@ -21,19 +23,17 @@ import java.util.List;
|
|||||||
|
|
||||||
public class AssetAndUrlModuleSourceProvider extends UrlModuleSourceProvider {
|
public class AssetAndUrlModuleSourceProvider extends UrlModuleSourceProvider {
|
||||||
|
|
||||||
private static final String MODULES_PATH = "modules";
|
|
||||||
private android.content.Context mContext;
|
private android.content.Context mContext;
|
||||||
private List<String> mModules;
|
private final URI mBaseURI;
|
||||||
private final URI mBaseURI = URI.create("file:///android_asset/modules");
|
private final String mAssetDirPath;
|
||||||
|
private final AssetManager mAssetManager;
|
||||||
|
|
||||||
public AssetAndUrlModuleSourceProvider(android.content.Context context, List<URI> list) {
|
public AssetAndUrlModuleSourceProvider(android.content.Context context, String assetDirPath, List<URI> list) {
|
||||||
super(list, null);
|
super(list, null);
|
||||||
mContext = context;
|
mContext = context;
|
||||||
try {
|
mAssetDirPath = assetDirPath;
|
||||||
mModules = Arrays.asList(mContext.getAssets().list(MODULES_PATH));
|
mBaseURI = URI.create("file:///android_asset/" + assetDirPath);
|
||||||
} catch (IOException e) {
|
mAssetManager = mContext.getAssets();
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -42,10 +42,11 @@ public class AssetAndUrlModuleSourceProvider extends UrlModuleSourceProvider {
|
|||||||
if (!moduleIdWithExtension.endsWith(".js")) {
|
if (!moduleIdWithExtension.endsWith(".js")) {
|
||||||
moduleIdWithExtension += ".js";
|
moduleIdWithExtension += ".js";
|
||||||
}
|
}
|
||||||
if (mModules.contains(moduleIdWithExtension)) {
|
try {
|
||||||
return new ModuleSource(new InputStreamReader(mContext.getAssets().open(MODULES_PATH + "/" + moduleIdWithExtension)), null,
|
return new ModuleSource(new InputStreamReader(mAssetManager.open(mAssetDirPath + "/" + moduleIdWithExtension)), null,
|
||||||
URI.create(moduleIdWithExtension), mBaseURI, validator);
|
new URI(mBaseURI.toString() + "/" + moduleIdWithExtension), mBaseURI, validator);
|
||||||
}
|
} catch (FileNotFoundException e) {
|
||||||
return super.loadFromPrivilegedLocations(moduleId, validator);
|
return super.loadFromPrivilegedLocations(moduleId, validator);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
@@ -49,6 +49,7 @@ public class RhinoJavaScriptEngine extends JavaScriptEngine {
|
|||||||
|
|
||||||
private static final String LOG_TAG = "RhinoJavaScriptEngine";
|
private static final String LOG_TAG = "RhinoJavaScriptEngine";
|
||||||
|
|
||||||
|
private static final String MODULES_PATH = "modules";
|
||||||
private static int contextCount = 0;
|
private static int contextCount = 0;
|
||||||
private static StringScriptSource sInitScript;
|
private static StringScriptSource sInitScript;
|
||||||
private static final ConcurrentHashMap<Context, RhinoJavaScriptEngine> sContextEngineMap = new ConcurrentHashMap<>();
|
private static final ConcurrentHashMap<Context, RhinoJavaScriptEngine> sContextEngineMap = new ConcurrentHashMap<>();
|
||||||
@@ -129,7 +130,7 @@ public class RhinoJavaScriptEngine extends JavaScriptEngine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void initRequireBuilder(Context context, Scriptable scope) {
|
void initRequireBuilder(Context context, Scriptable scope) {
|
||||||
AssetAndUrlModuleSourceProvider provider = new AssetAndUrlModuleSourceProvider(mAndroidContext,
|
AssetAndUrlModuleSourceProvider provider = new AssetAndUrlModuleSourceProvider(mAndroidContext, MODULES_PATH,
|
||||||
Collections.singletonList(new File("/").toURI()));
|
Collections.singletonList(new File("/").toURI()));
|
||||||
new RequireBuilder()
|
new RequireBuilder()
|
||||||
.setModuleScriptProvider(new SoftCachingModuleScriptProvider(provider))
|
.setModuleScriptProvider(new SoftCachingModuleScriptProvider(provider))
|
||||||
|
|||||||
@@ -4,14 +4,20 @@ import android.content.Context;
|
|||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
|
||||||
|
import com.stardust.autojs.engine.AssetAndUrlModuleSourceProvider;
|
||||||
import com.stardust.pio.PFiles;
|
import com.stardust.pio.PFiles;
|
||||||
import com.stardust.pio.UncheckedIOException;
|
import com.stardust.pio.UncheckedIOException;
|
||||||
|
|
||||||
import org.mozilla.javascript.Function;
|
import org.mozilla.javascript.Function;
|
||||||
|
import org.mozilla.javascript.ImporterTopLevel;
|
||||||
import org.mozilla.javascript.Scriptable;
|
import org.mozilla.javascript.Scriptable;
|
||||||
|
import org.mozilla.javascript.commonjs.module.RequireBuilder;
|
||||||
|
import org.mozilla.javascript.commonjs.module.provider.SoftCachingModuleScriptProvider;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
import java.util.concurrent.Executors;
|
import java.util.concurrent.Executors;
|
||||||
|
|
||||||
@@ -21,6 +27,7 @@ import java.util.concurrent.Executors;
|
|||||||
|
|
||||||
public class JsBeautifier {
|
public class JsBeautifier {
|
||||||
|
|
||||||
|
|
||||||
public interface Callback {
|
public interface Callback {
|
||||||
|
|
||||||
void onSuccess(String beautifiedCode);
|
void onSuccess(String beautifiedCode);
|
||||||
@@ -34,12 +41,14 @@ public class JsBeautifier {
|
|||||||
private org.mozilla.javascript.Context mScriptContext;
|
private org.mozilla.javascript.Context mScriptContext;
|
||||||
private Scriptable mScriptable;
|
private Scriptable mScriptable;
|
||||||
private final String mBeautifyJsPath;
|
private final String mBeautifyJsPath;
|
||||||
|
private final String mBeautifyJsDir;
|
||||||
private View mView;
|
private View mView;
|
||||||
|
|
||||||
public JsBeautifier(View view, String beautifyJsPath) {
|
public JsBeautifier(View view, String beautifyJsDirPath) {
|
||||||
mContext = view.getContext();
|
mContext = view.getContext();
|
||||||
mView = view;
|
mView = view;
|
||||||
mBeautifyJsPath = beautifyJsPath;
|
mBeautifyJsDir = beautifyJsDirPath;
|
||||||
|
mBeautifyJsPath = PFiles.join(beautifyJsDirPath, "beautify.js");
|
||||||
}
|
}
|
||||||
|
|
||||||
public void beautify(final String code, final Callback callback) {
|
public void beautify(final String code, final Callback callback) {
|
||||||
@@ -65,11 +74,24 @@ public class JsBeautifier {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void enterContext() {
|
private void enterContext() {
|
||||||
if (mScriptContext == null) {
|
if (mScriptContext != null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
mScriptContext = org.mozilla.javascript.Context.enter();
|
mScriptContext = org.mozilla.javascript.Context.enter();
|
||||||
mScriptContext.setLanguageVersion(org.mozilla.javascript.Context.VERSION_1_8);
|
mScriptContext.setLanguageVersion(org.mozilla.javascript.Context.VERSION_1_8);
|
||||||
mScriptContext.setOptimizationLevel(-1);
|
mScriptContext.setOptimizationLevel(-1);
|
||||||
|
if (mScriptable == null) {
|
||||||
|
ImporterTopLevel importerTopLevel = new ImporterTopLevel();
|
||||||
|
importerTopLevel.initStandardObjects(mScriptContext, false);
|
||||||
|
mScriptable = importerTopLevel;
|
||||||
}
|
}
|
||||||
|
AssetAndUrlModuleSourceProvider provider = new AssetAndUrlModuleSourceProvider(mContext, mBeautifyJsDir,
|
||||||
|
Collections.singletonList(new File("/").toURI()));
|
||||||
|
new RequireBuilder()
|
||||||
|
.setModuleScriptProvider(new SoftCachingModuleScriptProvider(provider))
|
||||||
|
.setSandboxed(false)
|
||||||
|
.createRequire(mScriptContext, mScriptable)
|
||||||
|
.install(mScriptable);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void prepare() {
|
public void prepare() {
|
||||||
@@ -93,8 +115,6 @@ public class JsBeautifier {
|
|||||||
try {
|
try {
|
||||||
enterContext();
|
enterContext();
|
||||||
InputStream is = mContext.getAssets().open(mBeautifyJsPath);
|
InputStream is = mContext.getAssets().open(mBeautifyJsPath);
|
||||||
if (mScriptable == null)
|
|
||||||
mScriptable = mScriptContext.initSafeStandardObjects();
|
|
||||||
mJsBeautifyFunction = (Function) mScriptContext.evaluateString(mScriptable, PFiles.read(is), "<js_beautify>", 1, null);
|
mJsBeautifyFunction = (Function) mScriptContext.evaluateString(mScriptable, PFiles.read(is), "<js_beautify>", 1, null);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
exitContext();
|
exitContext();
|
||||||
|
|||||||
Reference in New Issue
Block a user