Skip to content

Commit

Permalink
Switched to using a webview
Browse files Browse the repository at this point in the history
  • Loading branch information
harshad1 committed Oct 24, 2023
1 parent d8b8960 commit 4ff91d3
Show file tree
Hide file tree
Showing 6 changed files with 117 additions and 44 deletions.
7 changes: 2 additions & 5 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ if (enable_plugin_kotlin) {
apply plugin: 'kotlin-kapt'
}

rootProject.ext.version_minSdk = 18
rootProject.ext.version_minSdk = 20

// https://github.com/vsch/flexmark-java/releases
ext.version_library_flexmark = "0.42.14"
Expand Down Expand Up @@ -67,7 +67,7 @@ android {

buildTypes {
release {
minifyEnabled true
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
Expand Down Expand Up @@ -148,9 +148,6 @@ dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:${version_plugin_kotlin}"
}

// Javascript evaluator
implementation "com.github.seven332:quickjs-android:0.1.0"

// Processors
def anpros = []
for (anpro in anpros) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -600,7 +600,7 @@ protected final boolean runCommonAction(final @StringRes int action) {
}
case R.string.abid_common_insert_snippet: {
MarkorDialogFactory.showInsertSnippetDialog(_activity, (snip) -> {
_hlEditor.insertOrReplaceTextOnCursor(TextViewUtils.interpolatePlaceholders(snip, _document.getTitle()));
TextViewUtils.interpolatePlaceholders(snip, _document.getTitle(), _hlEditor::insertOrReplaceTextOnCursor);
_lastSnip = snip;
});
return true;
Expand Down Expand Up @@ -690,7 +690,7 @@ protected final boolean runCommonLongPressAction(@StringRes int action) {
}
case R.string.abid_common_insert_snippet: {
if (!TextUtils.isEmpty(_lastSnip)) {
_hlEditor.insertOrReplaceTextOnCursor(TextViewUtils.interpolatePlaceholders(_lastSnip, _document.getName()));
TextViewUtils.interpolatePlaceholders(_lastSnip, _document.getTitle(), _hlEditor::insertOrReplaceTextOnCursor);
}
return true;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -336,7 +336,7 @@ private Pair<byte[], Integer> getTemplateContent(final Spinner templateSpinner,
final Map<String, File> snippets = MarkorDialogFactory.getSnippets(ApplicationObject.settings());
if (templateSpinner.getSelectedItem() instanceof String && snippets.containsKey((String) templateSpinner.getSelectedItem())) {
final String text = GsFileUtils.readTextFileFast(snippets.get((String) templateSpinner.getSelectedItem())).first;
t = TextViewUtils.interpolatePlaceholders(text, GsFileUtils.getNameWithoutExtension(filename));
t = TextViewUtils.interpolateEscapedDateTime(text);
break;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
#########################################################*/
package net.gsantner.markor.frontend.textview;

import android.content.Context;
import android.content.res.Resources;
import android.graphics.Rect;
import android.os.Build;
Expand All @@ -23,18 +22,14 @@
import android.util.DisplayMetrics;
import android.view.View;
import android.view.WindowInsets;
import android.webkit.WebView;
import android.widget.EditText;
import android.widget.TextView;

import androidx.annotation.NonNull;

import com.hippo.quickjs.android.JSContext;
import com.hippo.quickjs.android.JSRuntime;
import com.hippo.quickjs.android.QuickJS;

import net.gsantner.markor.util.MarkorContextUtils;
import net.gsantner.markor.util.JSEvaluator;
import net.gsantner.opoc.format.GsTextUtils;
import net.gsantner.opoc.util.GsCollectionUtils;
import net.gsantner.opoc.util.GsContextUtils;
import net.gsantner.opoc.wrapper.GsCallback;

Expand All @@ -51,7 +46,7 @@
@SuppressWarnings({"CharsetObjectCanBeUsed", "WeakerAccess", "unused"})
public final class TextViewUtils extends GsTextUtils {

final static Pattern jsDelim = Pattern.compile("<%\\s(.*?)\\s%>");
private final static Pattern jsDelim = Pattern.compile("<%\\s(.*?)\\s%>", Pattern.DOTALL);

// Suppress default constructor for noninstantiability
private TextViewUtils() {
Expand Down Expand Up @@ -387,7 +382,11 @@ public static void setSelectionAndShow(final EditText edit, final int... sel) {
}
}

public static String interpolatePlaceholders(String text, final String title) {
public static void interpolatePlaceholders(
String text,
final String title,
final GsCallback.a1<String> callback
) {
final long current = System.currentTimeMillis();
final String time = GsContextUtils.instance.formatDateTime((Locale) null, "HH:mm", current);
final String date = GsContextUtils.instance.formatDateTime((Locale) null, "yyyy-MM-dd", current);
Expand All @@ -403,41 +402,52 @@ public static String interpolatePlaceholders(String text, final String title) {
.replace("{{title}}", title)
.replace("{{sel}}", HighlightingEditor.INSERT_SELECTION_HERE_TOKEN);

text = interpolateJS(text);

text = text.replace("{{cursor}}", HighlightingEditor.PLACE_CURSOR_HERE_TOKEN);
interpolateJS(text, (evald) -> {
evald = evald.replace("{{cursor}}", HighlightingEditor.PLACE_CURSOR_HERE_TOKEN);
callback.callback(evald);
});
}

return text;
private static class Region {
public final int start, end;
public final String result;
public Region(int start, int end, String result) {
this.end = end;
this.start = start;
this.result = result;
}
}

public static void interpolateJS(
final String text,
final GsCallback.a1<String> callback
) {
final Matcher matcher = jsDelim.matcher(text);
final List<Region> replaces = new ArrayList<>();

public static String interpolateJS(final String text) {
final QuickJS quickJS = new QuickJS.Builder().build();
try (JSRuntime runtime = quickJS.createJSRuntime()) {
try (JSContext context = runtime.createJSContext()) {
// Evaluate all the groups
final int[] count = new int[] { 0 };
while (matcher.find()) {
final String code = matcher.group(1);
final int start = matcher.start(), end = matcher.end();

final Matcher matcher = jsDelim.matcher(text);
final List<Integer> starts = new ArrayList<>();
final List<Integer> ends = new ArrayList<>();
final List<String> evals = new ArrayList<>();
// Only instantiatiated if a snippet actually has JS
JSEvaluator.getInstance().eval(code, (result) -> {
replaces.add(new Region(start, end, result));

// Evaluate all the groups
while (matcher.find()) {
final String code = matcher.group(1);
evals.add(context.evaluate(code, "", String.class));
starts.add(matcher.start());
ends.add(matcher.end());
}
if (replaces.size() == count[0]) {

final StringBuilder builder = new StringBuilder(text);
// When done, fill them in backwards to preserve indices
GsCollectionUtils.keySort(replaces, (r) -> -r.start);
final StringBuilder builder = new StringBuilder(text);
for (final Region r: replaces) {
builder.replace(r.start, r.end, r.result);
}

// Fill them in backwards to preserve indices
for (int i = (evals.size() - 1); i >= 0; i--) {
builder.replace(starts.get(i), ends.get(i), evals.get(i));
callback.callback(builder.toString());
}

return builder.toString();
}
});
count[0]++;
}
}

Expand Down
66 changes: 66 additions & 0 deletions app/src/main/java/net/gsantner/markor/util/JSEvaluator.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package net.gsantner.markor.util;

import android.annotation.SuppressLint;
import android.util.Log;
import android.webkit.WebSettings;
import android.webkit.WebView;

import net.gsantner.markor.ApplicationObject;
import net.gsantner.opoc.wrapper.GsCallback;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
* This class exists to provide a singleton WebView and some utilities
* for evaluating JavaScript.
*
* The WebView is a singleton as inflating it repeatedly can cause perf issues.
*/
public class JSEvaluator {
@SuppressLint("StaticFieldLeak")
private static JSEvaluator instance = null; // Not a problem as we use applicationContext

public static JSEvaluator getInstance() {
if (instance == null) {
instance = new JSEvaluator();
}
return instance;
}

// ----------------------------------------------

private final WebView webView;

private static final Pattern quotedString = Pattern.compile("\"(.*)\"");

@SuppressLint("SetJavaScriptEnabled")
private JSEvaluator() {
webView = new WebView(ApplicationObject.get().getApplicationContext());
final WebSettings settings = webView.getSettings();
settings.setDatabaseEnabled(false);
settings.setGeolocationEnabled(false);
settings.setJavaScriptEnabled(true);
settings.setAllowFileAccess(true);
settings.setAllowContentAccess(true);
settings.setAllowFileAccessFromFileURLs(true);
settings.setAllowUniversalAccessFromFileURLs(true);
}

public void eval(final String code, final GsCallback.a1<String> callback) {
try {
webView.evaluateJavascript(code, res -> {
if (res != null) {
final Matcher m = quotedString.matcher(res);
if (m.matches()) {
callback.callback(m.group(1));
} else {
callback.callback(res);
}
}
});
} catch (final Exception exception) {
Log.i(JSEvaluator.class.getName(), exception.toString());
}
}
}
2 changes: 1 addition & 1 deletion app/thirdparty-lib-src/QuadFlask-colorpicker/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ android {
}
buildTypes {
release {
minifyEnabled false
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
Expand Down

0 comments on commit 4ff91d3

Please sign in to comment.