POC for plugin system
This commit is contained in:
parent
340ce5753c
commit
498c811987
@ -9,7 +9,7 @@ import android.util.AttributeSet;
|
|||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
|
||||||
import ru.noties.markwon.R;
|
import ru.noties.markwon.R;
|
||||||
import ru.noties.markwon.spans.TaskListDrawable;
|
import ru.noties.markwon.tasklist.TaskListDrawable;
|
||||||
|
|
||||||
public class DebugCheckboxDrawableView extends View {
|
public class DebugCheckboxDrawableView extends View {
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@ import ru.noties.markwon.renderer.ImageSize;
|
|||||||
import ru.noties.markwon.renderer.ImageSizeResolver;
|
import ru.noties.markwon.renderer.ImageSizeResolver;
|
||||||
import ru.noties.markwon.spans.AsyncDrawable;
|
import ru.noties.markwon.spans.AsyncDrawable;
|
||||||
import ru.noties.markwon.spans.AsyncDrawableSpan;
|
import ru.noties.markwon.spans.AsyncDrawableSpan;
|
||||||
import ru.noties.markwon.spans.SpannableTheme;
|
import ru.noties.markwon.spans.MarkwonTheme;
|
||||||
|
|
||||||
public class GifAwareSpannableFactory extends SpannableFactoryDef {
|
public class GifAwareSpannableFactory extends SpannableFactoryDef {
|
||||||
|
|
||||||
@ -19,7 +19,7 @@ public class GifAwareSpannableFactory extends SpannableFactoryDef {
|
|||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
public Object image(@NonNull SpannableTheme theme, @NonNull String destination, @NonNull AsyncDrawable.Loader loader, @NonNull ImageSizeResolver imageSizeResolver, @Nullable ImageSize imageSize, boolean replacementTextIsLink) {
|
public Object image(@NonNull MarkwonTheme theme, @NonNull String destination, @NonNull AsyncDrawable.Loader loader, @NonNull ImageSizeResolver imageSizeResolver, @Nullable ImageSize imageSize, boolean replacementTextIsLink) {
|
||||||
return new AsyncDrawableSpan(
|
return new AsyncDrawableSpan(
|
||||||
theme,
|
theme,
|
||||||
new GifAwareAsyncDrawable(
|
new GifAwareAsyncDrawable(
|
||||||
|
@ -12,6 +12,9 @@ import android.widget.TextView;
|
|||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
import ru.noties.debug.Debug;
|
import ru.noties.debug.Debug;
|
||||||
|
import ru.noties.markwon.core.CorePlugin;
|
||||||
|
import ru.noties.markwon.tasklist.TaskListDrawable;
|
||||||
|
import ru.noties.markwon.tasklist.TaskListPlugin;
|
||||||
|
|
||||||
public class MainActivity extends Activity {
|
public class MainActivity extends Activity {
|
||||||
|
|
||||||
@ -40,7 +43,7 @@ public class MainActivity extends Activity {
|
|||||||
|
|
||||||
themes.apply(this);
|
themes.apply(this);
|
||||||
|
|
||||||
// how can we obtain SpannableConfiguration after theme was applied?
|
// how can we obtain MarkwonConfiguration after theme was applied?
|
||||||
// as we inject `themes` we won't be able to inject configuration, as it requires theme set
|
// as we inject `themes` we won't be able to inject configuration, as it requires theme set
|
||||||
|
|
||||||
setContentView(R.layout.activity_main);
|
setContentView(R.layout.activity_main);
|
||||||
@ -63,6 +66,16 @@ public class MainActivity extends Activity {
|
|||||||
|
|
||||||
appBarRenderer.render(appBarState());
|
appBarRenderer.render(appBarState());
|
||||||
|
|
||||||
|
if (true) {
|
||||||
|
final Markwon2 markwon2 = Markwon2.builder(this)
|
||||||
|
.use(new CorePlugin())
|
||||||
|
.use(TaskListPlugin.create(new TaskListDrawable(0xffff0000, 0xffff0000, -1)))
|
||||||
|
.build();
|
||||||
|
final CharSequence markdown = markwon2.markdown("**hello _dear_** `code`\n\n- [ ] first\n- [x] second");
|
||||||
|
textView.setText(markdown);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
markdownLoader.load(uri(), new MarkdownLoader.OnMarkdownTextLoaded() {
|
markdownLoader.load(uri(), new MarkdownLoader.OnMarkdownTextLoaded() {
|
||||||
@Override
|
@Override
|
||||||
public void apply(final String text) {
|
public void apply(final String text) {
|
||||||
|
@ -14,7 +14,7 @@ import javax.inject.Inject;
|
|||||||
|
|
||||||
import ru.noties.debug.Debug;
|
import ru.noties.debug.Debug;
|
||||||
import ru.noties.markwon.spans.AsyncDrawable;
|
import ru.noties.markwon.spans.AsyncDrawable;
|
||||||
import ru.noties.markwon.spans.SpannableTheme;
|
import ru.noties.markwon.spans.MarkwonTheme;
|
||||||
import ru.noties.markwon.syntax.Prism4jSyntaxHighlight;
|
import ru.noties.markwon.syntax.Prism4jSyntaxHighlight;
|
||||||
import ru.noties.markwon.syntax.Prism4jTheme;
|
import ru.noties.markwon.syntax.Prism4jTheme;
|
||||||
import ru.noties.markwon.syntax.Prism4jThemeDarkula;
|
import ru.noties.markwon.syntax.Prism4jThemeDarkula;
|
||||||
@ -87,11 +87,11 @@ public class MarkdownRenderer {
|
|||||||
0x20000000
|
0x20000000
|
||||||
);
|
);
|
||||||
|
|
||||||
final SpannableConfiguration configuration = SpannableConfiguration.builder(context)
|
final MarkwonConfiguration configuration = MarkwonConfiguration.builder(context)
|
||||||
.asyncDrawableLoader(loader)
|
.asyncDrawableLoader(loader)
|
||||||
.urlProcessor(urlProcessor)
|
.urlProcessor(urlProcessor)
|
||||||
.syntaxHighlight(Prism4jSyntaxHighlight.create(prism4j, prism4jTheme))
|
.syntaxHighlight(Prism4jSyntaxHighlight.create(prism4j, prism4jTheme))
|
||||||
.theme(SpannableTheme.builderWithDefaults(context)
|
.theme(MarkwonTheme.builderWithDefaults(context)
|
||||||
.codeBackgroundColor(background)
|
.codeBackgroundColor(background)
|
||||||
.codeTextColor(prism4jTheme.textColor())
|
.codeTextColor(prism4jTheme.textColor())
|
||||||
.build())
|
.build())
|
||||||
|
@ -209,4 +209,4 @@ Background of header table row
|
|||||||
|
|
||||||
Drawable of task list item
|
Drawable of task list item
|
||||||
|
|
||||||
<ThemeProperty name="taskListDrawable" type="android.graphics.drawable.Drawable" defaults="ru.noties.markwon.spans.TaskListDrawable" />
|
<ThemeProperty name="taskListDrawable" type="android.graphics.drawable.Drawable" defaults="ru.noties.markwon.tasklist.TaskListDrawable" />
|
||||||
|
@ -3,27 +3,27 @@ package ru.noties.markwon.view.debug;
|
|||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
|
|
||||||
import ru.noties.markwon.SpannableConfiguration;
|
import ru.noties.markwon.MarkwonConfiguration;
|
||||||
import ru.noties.markwon.spans.SpannableTheme;
|
import ru.noties.markwon.spans.MarkwonTheme;
|
||||||
import ru.noties.markwon.view.IMarkwonView;
|
import ru.noties.markwon.view.IMarkwonView;
|
||||||
|
|
||||||
public class DebugConfigurationProvider implements IMarkwonView.ConfigurationProvider {
|
public class DebugConfigurationProvider implements IMarkwonView.ConfigurationProvider {
|
||||||
|
|
||||||
private SpannableConfiguration cached;
|
private MarkwonConfiguration cached;
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
@Override
|
@Override
|
||||||
public SpannableConfiguration provide(@NonNull Context context) {
|
public MarkwonConfiguration provide(@NonNull Context context) {
|
||||||
if (cached == null) {
|
if (cached == null) {
|
||||||
cached = SpannableConfiguration.builder(context)
|
cached = MarkwonConfiguration.builder(context)
|
||||||
.theme(debugTheme(context))
|
.theme(debugTheme(context))
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
return cached;
|
return cached;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static SpannableTheme debugTheme(@NonNull Context context) {
|
private static MarkwonTheme debugTheme(@NonNull Context context) {
|
||||||
return SpannableTheme.builderWithDefaults(context)
|
return MarkwonTheme.builderWithDefaults(context)
|
||||||
.blockQuoteColor(0xFFff0000)
|
.blockQuoteColor(0xFFff0000)
|
||||||
.codeBackgroundColor(0x40FF0000)
|
.codeBackgroundColor(0x40FF0000)
|
||||||
.build();
|
.build();
|
||||||
|
@ -4,19 +4,19 @@ import android.content.Context;
|
|||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
|
|
||||||
import ru.noties.markwon.SpannableConfiguration;
|
import ru.noties.markwon.MarkwonConfiguration;
|
||||||
|
|
||||||
public interface IMarkwonView {
|
public interface IMarkwonView {
|
||||||
|
|
||||||
interface ConfigurationProvider {
|
interface ConfigurationProvider {
|
||||||
@NonNull
|
@NonNull
|
||||||
SpannableConfiguration provide(@NonNull Context context);
|
MarkwonConfiguration provide(@NonNull Context context);
|
||||||
}
|
}
|
||||||
|
|
||||||
void setConfigurationProvider(@NonNull ConfigurationProvider provider);
|
void setConfigurationProvider(@NonNull ConfigurationProvider provider);
|
||||||
|
|
||||||
void setMarkdown(@Nullable String markdown);
|
void setMarkdown(@Nullable String markdown);
|
||||||
void setMarkdown(@Nullable SpannableConfiguration configuration, @Nullable String markdown);
|
void setMarkdown(@Nullable MarkwonConfiguration configuration, @Nullable String markdown);
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
String getMarkdown();
|
String getMarkdown();
|
||||||
|
@ -7,7 +7,7 @@ import android.support.annotation.Nullable;
|
|||||||
import android.util.AttributeSet;
|
import android.util.AttributeSet;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import ru.noties.markwon.SpannableConfiguration;
|
import ru.noties.markwon.MarkwonConfiguration;
|
||||||
|
|
||||||
@SuppressLint("AppCompatCustomView")
|
@SuppressLint("AppCompatCustomView")
|
||||||
public class MarkwonView extends TextView implements IMarkwonView {
|
public class MarkwonView extends TextView implements IMarkwonView {
|
||||||
@ -38,7 +38,7 @@ public class MarkwonView extends TextView implements IMarkwonView {
|
|||||||
helper.setMarkdown(markdown);
|
helper.setMarkdown(markdown);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setMarkdown(@Nullable SpannableConfiguration configuration, @Nullable String markdown) {
|
public void setMarkdown(@Nullable MarkwonConfiguration configuration, @Nullable String markdown) {
|
||||||
helper.setMarkdown(configuration, markdown);
|
helper.setMarkdown(configuration, markdown);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,7 +6,7 @@ import android.support.annotation.Nullable;
|
|||||||
import android.support.v7.widget.AppCompatTextView;
|
import android.support.v7.widget.AppCompatTextView;
|
||||||
import android.util.AttributeSet;
|
import android.util.AttributeSet;
|
||||||
|
|
||||||
import ru.noties.markwon.SpannableConfiguration;
|
import ru.noties.markwon.MarkwonConfiguration;
|
||||||
|
|
||||||
public class MarkwonViewCompat extends AppCompatTextView implements IMarkwonView {
|
public class MarkwonViewCompat extends AppCompatTextView implements IMarkwonView {
|
||||||
|
|
||||||
@ -38,7 +38,7 @@ public class MarkwonViewCompat extends AppCompatTextView implements IMarkwonView
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setMarkdown(@Nullable SpannableConfiguration configuration, @Nullable String markdown) {
|
public void setMarkdown(@Nullable MarkwonConfiguration configuration, @Nullable String markdown) {
|
||||||
helper.setMarkdown(configuration, markdown);
|
helper.setMarkdown(configuration, markdown);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,7 +9,7 @@ import android.util.AttributeSet;
|
|||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import ru.noties.markwon.Markwon;
|
import ru.noties.markwon.Markwon;
|
||||||
import ru.noties.markwon.SpannableConfiguration;
|
import ru.noties.markwon.MarkwonConfiguration;
|
||||||
|
|
||||||
public class MarkwonViewHelper implements IMarkwonView {
|
public class MarkwonViewHelper implements IMarkwonView {
|
||||||
|
|
||||||
@ -21,7 +21,7 @@ public class MarkwonViewHelper implements IMarkwonView {
|
|||||||
|
|
||||||
private ConfigurationProvider provider;
|
private ConfigurationProvider provider;
|
||||||
|
|
||||||
private SpannableConfiguration configuration;
|
private MarkwonConfiguration configuration;
|
||||||
private String markdown;
|
private String markdown;
|
||||||
|
|
||||||
private MarkwonViewHelper(@NonNull TextView textView) {
|
private MarkwonViewHelper(@NonNull TextView textView) {
|
||||||
@ -71,14 +71,14 @@ public class MarkwonViewHelper implements IMarkwonView {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setMarkdown(@Nullable SpannableConfiguration configuration, @Nullable String markdown) {
|
public void setMarkdown(@Nullable MarkwonConfiguration configuration, @Nullable String markdown) {
|
||||||
this.markdown = markdown;
|
this.markdown = markdown;
|
||||||
if (configuration == null) {
|
if (configuration == null) {
|
||||||
if (this.configuration == null) {
|
if (this.configuration == null) {
|
||||||
if (provider != null) {
|
if (provider != null) {
|
||||||
this.configuration = provider.provide(textView.getContext());
|
this.configuration = provider.provide(textView.getContext());
|
||||||
} else {
|
} else {
|
||||||
this.configuration = SpannableConfiguration.create(textView.getContext());
|
this.configuration = MarkwonConfiguration.create(textView.getContext());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
configuration = this.configuration;
|
configuration = this.configuration;
|
||||||
|
@ -0,0 +1,46 @@
|
|||||||
|
package ru.noties.markwon;
|
||||||
|
|
||||||
|
import android.support.annotation.NonNull;
|
||||||
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import org.commonmark.parser.Parser;
|
||||||
|
|
||||||
|
import ru.noties.markwon.spans.MarkwonTheme;
|
||||||
|
|
||||||
|
public abstract class AbstractMarkwonPlugin implements MarkwonPlugin {
|
||||||
|
@Override
|
||||||
|
public void configureParser(@NonNull Parser.Builder builder) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void configureTheme(@NonNull MarkwonTheme.Builder builder) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void configureConfiguration(@NonNull MarkwonConfiguration.Builder builder) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void configureVisitor(@NonNull MarkwonVisitor.Builder builder) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@Override
|
||||||
|
public String processMarkdown(@NonNull String markdown) {
|
||||||
|
return markdown;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void beforeSetText(@NonNull TextView textView, @NonNull SpannableBuilder builder) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void afterSetText(@NonNull TextView textView, @NonNull SpannableBuilder builder) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -40,11 +40,11 @@ public abstract class Markwon {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see #setMarkdown(TextView, SpannableConfiguration, String)
|
* @see #setMarkdown(TextView, MarkwonConfiguration, String)
|
||||||
* @since 1.0.0
|
* @since 1.0.0
|
||||||
*/
|
*/
|
||||||
public static void setMarkdown(@NonNull TextView view, @NonNull String markdown) {
|
public static void setMarkdown(@NonNull TextView view, @NonNull String markdown) {
|
||||||
setMarkdown(view, SpannableConfiguration.create(view.getContext()), markdown);
|
setMarkdown(view, MarkwonConfiguration.create(view.getContext()), markdown);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -52,16 +52,16 @@ public abstract class Markwon {
|
|||||||
* and applies it to view
|
* and applies it to view
|
||||||
*
|
*
|
||||||
* @param view {@link TextView} to set markdown into
|
* @param view {@link TextView} to set markdown into
|
||||||
* @param configuration a {@link SpannableConfiguration} instance
|
* @param configuration a {@link MarkwonConfiguration} instance
|
||||||
* @param markdown raw markdown String (for example: {@code `**Hello**`})
|
* @param markdown raw markdown String (for example: {@code `**Hello**`})
|
||||||
* @see #markdown(SpannableConfiguration, String)
|
* @see #markdown(MarkwonConfiguration, String)
|
||||||
* @see #setText(TextView, CharSequence)
|
* @see #setText(TextView, CharSequence)
|
||||||
* @see SpannableConfiguration
|
* @see MarkwonConfiguration
|
||||||
* @since 1.0.0
|
* @since 1.0.0
|
||||||
*/
|
*/
|
||||||
public static void setMarkdown(
|
public static void setMarkdown(
|
||||||
@NonNull TextView view,
|
@NonNull TextView view,
|
||||||
@NonNull SpannableConfiguration configuration,
|
@NonNull MarkwonConfiguration configuration,
|
||||||
@NonNull String markdown
|
@NonNull String markdown
|
||||||
) {
|
) {
|
||||||
|
|
||||||
@ -117,7 +117,7 @@ public abstract class Markwon {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns parsed markdown with default {@link SpannableConfiguration} obtained from {@link Context}
|
* Returns parsed markdown with default {@link MarkwonConfiguration} obtained from {@link Context}
|
||||||
*
|
*
|
||||||
* @param context {@link Context}
|
* @param context {@link Context}
|
||||||
* @param markdown raw markdown
|
* @param markdown raw markdown
|
||||||
@ -126,21 +126,21 @@ public abstract class Markwon {
|
|||||||
*/
|
*/
|
||||||
@NonNull
|
@NonNull
|
||||||
public static CharSequence markdown(@NonNull Context context, @NonNull String markdown) {
|
public static CharSequence markdown(@NonNull Context context, @NonNull String markdown) {
|
||||||
final SpannableConfiguration configuration = SpannableConfiguration.create(context);
|
final MarkwonConfiguration configuration = MarkwonConfiguration.create(context);
|
||||||
return markdown(configuration, markdown);
|
return markdown(configuration, markdown);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns parsed markdown with provided {@link SpannableConfiguration}
|
* Returns parsed markdown with provided {@link MarkwonConfiguration}
|
||||||
*
|
*
|
||||||
* @param configuration a {@link SpannableConfiguration}
|
* @param configuration a {@link MarkwonConfiguration}
|
||||||
* @param markdown raw markdown
|
* @param markdown raw markdown
|
||||||
* @return parsed markdown
|
* @return parsed markdown
|
||||||
* @see SpannableConfiguration
|
* @see MarkwonConfiguration
|
||||||
* @since 1.0.0
|
* @since 1.0.0
|
||||||
*/
|
*/
|
||||||
@NonNull
|
@NonNull
|
||||||
public static CharSequence markdown(@NonNull SpannableConfiguration configuration, @NonNull String markdown) {
|
public static CharSequence markdown(@NonNull MarkwonConfiguration configuration, @NonNull String markdown) {
|
||||||
final Parser parser = createParser();
|
final Parser parser = createParser();
|
||||||
final Node node = parser.parse(markdown);
|
final Node node = parser.parse(markdown);
|
||||||
final SpannableRenderer renderer = new SpannableRenderer();
|
final SpannableRenderer renderer = new SpannableRenderer();
|
||||||
|
32
markwon/src/main/java/ru/noties/markwon/Markwon2.java
Normal file
32
markwon/src/main/java/ru/noties/markwon/Markwon2.java
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
package ru.noties.markwon;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.support.annotation.NonNull;
|
||||||
|
|
||||||
|
import org.commonmark.node.Node;
|
||||||
|
|
||||||
|
public abstract class Markwon2 {
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
public static Builder builder(@NonNull Context context) {
|
||||||
|
return new MarkwonBuilderImpl(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
public abstract Node parse(@NonNull String input);
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
public abstract CharSequence render(@NonNull Node node);
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
public abstract CharSequence markdown(@NonNull String input);
|
||||||
|
|
||||||
|
public interface Builder {
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
Builder use(@NonNull MarkwonPlugin plugin);
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
Markwon2 build();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,53 @@
|
|||||||
|
package ru.noties.markwon;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.support.annotation.NonNull;
|
||||||
|
|
||||||
|
import org.commonmark.parser.Parser;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import ru.noties.markwon.spans.MarkwonTheme;
|
||||||
|
|
||||||
|
class MarkwonBuilderImpl implements Markwon2.Builder {
|
||||||
|
|
||||||
|
private final Context context;
|
||||||
|
|
||||||
|
private final List<MarkwonPlugin> plugins = new ArrayList<>(3);
|
||||||
|
|
||||||
|
MarkwonBuilderImpl(@NonNull Context context) {
|
||||||
|
this.context = context;
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@Override
|
||||||
|
public Markwon2.Builder use(@NonNull MarkwonPlugin plugin) {
|
||||||
|
plugins.add(plugin);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@Override
|
||||||
|
public Markwon2 build() {
|
||||||
|
|
||||||
|
final Parser.Builder parserBuilder = new Parser.Builder();
|
||||||
|
final MarkwonTheme.Builder themeBuilder = MarkwonTheme.builderWithDefaults(context);
|
||||||
|
final MarkwonConfiguration.Builder configurationBuilder = new MarkwonConfiguration.Builder(context);
|
||||||
|
final MarkwonVisitor.Builder visitorBuilder = new MarkwonVisitorImpl.BuilderImpl();
|
||||||
|
|
||||||
|
for (MarkwonPlugin plugin : plugins) {
|
||||||
|
plugin.configureParser(parserBuilder);
|
||||||
|
plugin.configureTheme(themeBuilder);
|
||||||
|
plugin.configureConfiguration(configurationBuilder);
|
||||||
|
plugin.configureVisitor(visitorBuilder);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new MarkwonImpl(
|
||||||
|
parserBuilder.build(),
|
||||||
|
visitorBuilder.build(themeBuilder.build(), configurationBuilder.build()),
|
||||||
|
Collections.unmodifiableList(plugins)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -9,14 +9,17 @@ import ru.noties.markwon.renderer.ImageSizeResolverDef;
|
|||||||
import ru.noties.markwon.renderer.html2.MarkwonHtmlRenderer;
|
import ru.noties.markwon.renderer.html2.MarkwonHtmlRenderer;
|
||||||
import ru.noties.markwon.spans.AsyncDrawable;
|
import ru.noties.markwon.spans.AsyncDrawable;
|
||||||
import ru.noties.markwon.spans.LinkSpan;
|
import ru.noties.markwon.spans.LinkSpan;
|
||||||
import ru.noties.markwon.spans.SpannableTheme;
|
import ru.noties.markwon.spans.MarkwonTheme;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* since 3.0.0 renamed `SpannableConfiguration` -> `MarkwonConfiguration`
|
||||||
|
*/
|
||||||
@SuppressWarnings("WeakerAccess")
|
@SuppressWarnings("WeakerAccess")
|
||||||
public class SpannableConfiguration {
|
public class MarkwonConfiguration {
|
||||||
|
|
||||||
// creates default configuration
|
// creates default configuration
|
||||||
@NonNull
|
@NonNull
|
||||||
public static SpannableConfiguration create(@NonNull Context context) {
|
public static MarkwonConfiguration create(@NonNull Context context) {
|
||||||
return new Builder(context).build();
|
return new Builder(context).build();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -25,7 +28,9 @@ public class SpannableConfiguration {
|
|||||||
return new Builder(context);
|
return new Builder(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
private final SpannableTheme theme;
|
@Deprecated
|
||||||
|
private final MarkwonTheme theme;
|
||||||
|
|
||||||
private final AsyncDrawable.Loader asyncDrawableLoader;
|
private final AsyncDrawable.Loader asyncDrawableLoader;
|
||||||
private final SyntaxHighlight syntaxHighlight;
|
private final SyntaxHighlight syntaxHighlight;
|
||||||
private final LinkSpan.Resolver linkResolver;
|
private final LinkSpan.Resolver linkResolver;
|
||||||
@ -37,7 +42,7 @@ public class SpannableConfiguration {
|
|||||||
private final MarkwonHtmlRenderer htmlRenderer; // @since 2.0.0
|
private final MarkwonHtmlRenderer htmlRenderer; // @since 2.0.0
|
||||||
private final boolean htmlAllowNonClosedTags; // @since 2.0.0
|
private final boolean htmlAllowNonClosedTags; // @since 2.0.0
|
||||||
|
|
||||||
private SpannableConfiguration(@NonNull Builder builder) {
|
private MarkwonConfiguration(@NonNull Builder builder) {
|
||||||
this.theme = builder.theme;
|
this.theme = builder.theme;
|
||||||
this.asyncDrawableLoader = builder.asyncDrawableLoader;
|
this.asyncDrawableLoader = builder.asyncDrawableLoader;
|
||||||
this.syntaxHighlight = builder.syntaxHighlight;
|
this.syntaxHighlight = builder.syntaxHighlight;
|
||||||
@ -60,7 +65,8 @@ public class SpannableConfiguration {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
public SpannableTheme theme() {
|
@Deprecated
|
||||||
|
public MarkwonTheme theme() {
|
||||||
return theme;
|
return theme;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -130,7 +136,9 @@ public class SpannableConfiguration {
|
|||||||
public static class Builder {
|
public static class Builder {
|
||||||
|
|
||||||
private final Context context;
|
private final Context context;
|
||||||
private SpannableTheme theme;
|
|
||||||
|
@Deprecated
|
||||||
|
private MarkwonTheme theme;
|
||||||
private AsyncDrawable.Loader asyncDrawableLoader;
|
private AsyncDrawable.Loader asyncDrawableLoader;
|
||||||
private SyntaxHighlight syntaxHighlight;
|
private SyntaxHighlight syntaxHighlight;
|
||||||
private LinkSpan.Resolver linkResolver;
|
private LinkSpan.Resolver linkResolver;
|
||||||
@ -146,7 +154,7 @@ public class SpannableConfiguration {
|
|||||||
this.context = context;
|
this.context = context;
|
||||||
}
|
}
|
||||||
|
|
||||||
Builder(@NonNull Context context, @NonNull SpannableConfiguration configuration) {
|
Builder(@NonNull Context context, @NonNull MarkwonConfiguration configuration) {
|
||||||
this(context);
|
this(context);
|
||||||
this.theme = configuration.theme;
|
this.theme = configuration.theme;
|
||||||
this.asyncDrawableLoader = configuration.asyncDrawableLoader;
|
this.asyncDrawableLoader = configuration.asyncDrawableLoader;
|
||||||
@ -162,7 +170,8 @@ public class SpannableConfiguration {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
public Builder theme(@NonNull SpannableTheme theme) {
|
@Deprecated
|
||||||
|
public Builder theme(@NonNull MarkwonTheme theme) {
|
||||||
this.theme = theme;
|
this.theme = theme;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
@ -254,10 +263,10 @@ public class SpannableConfiguration {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
public SpannableConfiguration build() {
|
public MarkwonConfiguration build() {
|
||||||
|
|
||||||
if (theme == null) {
|
if (theme == null) {
|
||||||
theme = SpannableTheme.create(context);
|
theme = MarkwonTheme.create(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (asyncDrawableLoader == null) {
|
if (asyncDrawableLoader == null) {
|
||||||
@ -300,7 +309,7 @@ public class SpannableConfiguration {
|
|||||||
htmlRenderer = MarkwonHtmlRenderer.create();
|
htmlRenderer = MarkwonHtmlRenderer.create();
|
||||||
}
|
}
|
||||||
|
|
||||||
return new SpannableConfiguration(this);
|
return new MarkwonConfiguration(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
48
markwon/src/main/java/ru/noties/markwon/MarkwonImpl.java
Normal file
48
markwon/src/main/java/ru/noties/markwon/MarkwonImpl.java
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
package ru.noties.markwon;
|
||||||
|
|
||||||
|
import android.support.annotation.NonNull;
|
||||||
|
|
||||||
|
import org.commonmark.node.Node;
|
||||||
|
import org.commonmark.parser.Parser;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
class MarkwonImpl extends Markwon2 {
|
||||||
|
|
||||||
|
private final Parser parser;
|
||||||
|
private final MarkwonVisitor visitor;
|
||||||
|
private final List<MarkwonPlugin> plugins;
|
||||||
|
|
||||||
|
MarkwonImpl(
|
||||||
|
@NonNull Parser parser,
|
||||||
|
@NonNull MarkwonVisitor visitor,
|
||||||
|
@NonNull List<MarkwonPlugin> plugins) {
|
||||||
|
this.parser = parser;
|
||||||
|
this.visitor = visitor;
|
||||||
|
this.plugins = plugins;
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@Override
|
||||||
|
public Node parse(@NonNull String input) {
|
||||||
|
|
||||||
|
for (MarkwonPlugin plugin : plugins) {
|
||||||
|
input = plugin.processMarkdown(input);
|
||||||
|
}
|
||||||
|
|
||||||
|
return parser.parse(input);
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@Override
|
||||||
|
public CharSequence render(@NonNull Node node) {
|
||||||
|
node.accept(visitor);
|
||||||
|
return visitor.builder().text();
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@Override
|
||||||
|
public CharSequence markdown(@NonNull String input) {
|
||||||
|
return render(parse(input));
|
||||||
|
}
|
||||||
|
}
|
29
markwon/src/main/java/ru/noties/markwon/MarkwonPlugin.java
Normal file
29
markwon/src/main/java/ru/noties/markwon/MarkwonPlugin.java
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
package ru.noties.markwon;
|
||||||
|
|
||||||
|
import android.support.annotation.NonNull;
|
||||||
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import org.commonmark.parser.Parser;
|
||||||
|
|
||||||
|
import ru.noties.markwon.spans.MarkwonTheme;
|
||||||
|
|
||||||
|
public interface MarkwonPlugin {
|
||||||
|
|
||||||
|
void configureParser(@NonNull Parser.Builder builder);
|
||||||
|
|
||||||
|
void configureTheme(@NonNull MarkwonTheme.Builder builder);
|
||||||
|
|
||||||
|
void configureConfiguration(@NonNull MarkwonConfiguration.Builder builder);
|
||||||
|
|
||||||
|
void configureVisitor(@NonNull MarkwonVisitor.Builder builder);
|
||||||
|
|
||||||
|
// images
|
||||||
|
// html
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
String processMarkdown(@NonNull String markdown);
|
||||||
|
|
||||||
|
void beforeSetText(@NonNull TextView textView, @NonNull SpannableBuilder builder);
|
||||||
|
|
||||||
|
void afterSetText(@NonNull TextView textView, @NonNull SpannableBuilder builder);
|
||||||
|
}
|
60
markwon/src/main/java/ru/noties/markwon/MarkwonVisitor.java
Normal file
60
markwon/src/main/java/ru/noties/markwon/MarkwonVisitor.java
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
package ru.noties.markwon;
|
||||||
|
|
||||||
|
import android.support.annotation.NonNull;
|
||||||
|
import android.support.annotation.Nullable;
|
||||||
|
|
||||||
|
import org.commonmark.node.Node;
|
||||||
|
import org.commonmark.node.Visitor;
|
||||||
|
|
||||||
|
import ru.noties.markwon.spans.MarkwonTheme;
|
||||||
|
|
||||||
|
public interface MarkwonVisitor extends Visitor {
|
||||||
|
|
||||||
|
interface NodeVisitor<N extends Node> {
|
||||||
|
void visit(@NonNull MarkwonVisitor visitor, @NonNull N n);
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Builder {
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
<N extends Node> Builder on(@NonNull Class<N> node, @NonNull NodeVisitor<N> nodeVisitor);
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
MarkwonVisitor build(@NonNull MarkwonTheme theme, @NonNull MarkwonConfiguration configuration);
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
MarkwonTheme theme();
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
MarkwonConfiguration configuration();
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
SpannableBuilder builder();
|
||||||
|
|
||||||
|
void visitChildren(@NonNull Node node);
|
||||||
|
|
||||||
|
boolean hasNext(@NonNull Node node);
|
||||||
|
|
||||||
|
void incrementBlockQuoteIndent();
|
||||||
|
|
||||||
|
void decrementBlockQuoteIndent();
|
||||||
|
|
||||||
|
void blockQuoteIntent(int blockQuoteIndent);
|
||||||
|
|
||||||
|
int blockQuoteIndent();
|
||||||
|
|
||||||
|
void incrementListLevel();
|
||||||
|
|
||||||
|
void decrementListLevel();
|
||||||
|
|
||||||
|
int listLevel();
|
||||||
|
|
||||||
|
void ensureNewLine();
|
||||||
|
|
||||||
|
void forceNewLine();
|
||||||
|
|
||||||
|
int length();
|
||||||
|
|
||||||
|
void setSpans(int start, @Nullable Object spans);
|
||||||
|
}
|
290
markwon/src/main/java/ru/noties/markwon/MarkwonVisitorImpl.java
Normal file
290
markwon/src/main/java/ru/noties/markwon/MarkwonVisitorImpl.java
Normal file
@ -0,0 +1,290 @@
|
|||||||
|
package ru.noties.markwon;
|
||||||
|
|
||||||
|
import android.support.annotation.NonNull;
|
||||||
|
import android.support.annotation.Nullable;
|
||||||
|
|
||||||
|
import org.commonmark.node.BlockQuote;
|
||||||
|
import org.commonmark.node.BulletList;
|
||||||
|
import org.commonmark.node.Code;
|
||||||
|
import org.commonmark.node.CustomBlock;
|
||||||
|
import org.commonmark.node.CustomNode;
|
||||||
|
import org.commonmark.node.Document;
|
||||||
|
import org.commonmark.node.Emphasis;
|
||||||
|
import org.commonmark.node.FencedCodeBlock;
|
||||||
|
import org.commonmark.node.HardLineBreak;
|
||||||
|
import org.commonmark.node.Heading;
|
||||||
|
import org.commonmark.node.HtmlBlock;
|
||||||
|
import org.commonmark.node.HtmlInline;
|
||||||
|
import org.commonmark.node.Image;
|
||||||
|
import org.commonmark.node.IndentedCodeBlock;
|
||||||
|
import org.commonmark.node.Link;
|
||||||
|
import org.commonmark.node.ListItem;
|
||||||
|
import org.commonmark.node.Node;
|
||||||
|
import org.commonmark.node.OrderedList;
|
||||||
|
import org.commonmark.node.Paragraph;
|
||||||
|
import org.commonmark.node.SoftLineBreak;
|
||||||
|
import org.commonmark.node.StrongEmphasis;
|
||||||
|
import org.commonmark.node.Text;
|
||||||
|
import org.commonmark.node.ThematicBreak;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import ru.noties.markwon.spans.MarkwonTheme;
|
||||||
|
|
||||||
|
class MarkwonVisitorImpl implements MarkwonVisitor {
|
||||||
|
|
||||||
|
private final Map<Class<? extends Node>, NodeVisitor<? extends Node>> nodes;
|
||||||
|
|
||||||
|
private final MarkwonTheme theme;
|
||||||
|
private final MarkwonConfiguration configuration;
|
||||||
|
private final SpannableBuilder builder = new SpannableBuilder();
|
||||||
|
|
||||||
|
private int blockQuoteIndent;
|
||||||
|
private int listLevel;
|
||||||
|
|
||||||
|
private MarkwonVisitorImpl(
|
||||||
|
@NonNull MarkwonTheme theme,
|
||||||
|
@NonNull MarkwonConfiguration configuration,
|
||||||
|
@NonNull Map<Class<? extends Node>, NodeVisitor<? extends Node>> nodes) {
|
||||||
|
this.theme = theme;
|
||||||
|
this.configuration = configuration;
|
||||||
|
this.nodes = nodes;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(BlockQuote blockQuote) {
|
||||||
|
visit((Node) blockQuote);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(BulletList bulletList) {
|
||||||
|
visit((Node) bulletList);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(Code code) {
|
||||||
|
visit((Node) code);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(Document document) {
|
||||||
|
visit((Node) document);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(Emphasis emphasis) {
|
||||||
|
visit((Node) emphasis);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(FencedCodeBlock fencedCodeBlock) {
|
||||||
|
visit((Node) fencedCodeBlock);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(HardLineBreak hardLineBreak) {
|
||||||
|
visit((Node) hardLineBreak);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(Heading heading) {
|
||||||
|
visit((Node) heading);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(ThematicBreak thematicBreak) {
|
||||||
|
visit((Node) thematicBreak);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(HtmlInline htmlInline) {
|
||||||
|
visit((Node) htmlInline);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(HtmlBlock htmlBlock) {
|
||||||
|
visit((Node) htmlBlock);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(Image image) {
|
||||||
|
visit((Node) image);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(IndentedCodeBlock indentedCodeBlock) {
|
||||||
|
visit((Node) indentedCodeBlock);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(Link link) {
|
||||||
|
visit((Node) link);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(ListItem listItem) {
|
||||||
|
visit((Node) listItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(OrderedList orderedList) {
|
||||||
|
visit((Node) orderedList);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(Paragraph paragraph) {
|
||||||
|
visit((Node) paragraph);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(SoftLineBreak softLineBreak) {
|
||||||
|
visit((Node) softLineBreak);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(StrongEmphasis strongEmphasis) {
|
||||||
|
visit((Node) strongEmphasis);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(Text text) {
|
||||||
|
visit((Node) text);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(CustomBlock customBlock) {
|
||||||
|
visit((Node) customBlock);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(CustomNode customNode) {
|
||||||
|
visit((Node) customNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void visit(@NonNull Node node) {
|
||||||
|
//noinspection unchecked
|
||||||
|
final NodeVisitor<Node> nodeVisitor = (NodeVisitor<Node>) nodes.get(node.getClass());
|
||||||
|
if (nodeVisitor != null) {
|
||||||
|
nodeVisitor.visit(this, node);
|
||||||
|
} else {
|
||||||
|
visitChildren(node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@Override
|
||||||
|
public MarkwonTheme theme() {
|
||||||
|
return theme;
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@Override
|
||||||
|
public MarkwonConfiguration configuration() {
|
||||||
|
return configuration;
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@Override
|
||||||
|
public SpannableBuilder builder() {
|
||||||
|
return builder;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visitChildren(@NonNull Node parent) {
|
||||||
|
Node node = parent.getFirstChild();
|
||||||
|
while (node != null) {
|
||||||
|
// A subclass of this visitor might modify the node, resulting in getNext returning a different node or no
|
||||||
|
// node after visiting it. So get the next node before visiting.
|
||||||
|
Node next = node.getNext();
|
||||||
|
node.accept(this);
|
||||||
|
node = next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasNext(@NonNull Node node) {
|
||||||
|
return node.getNext() != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void incrementBlockQuoteIndent() {
|
||||||
|
blockQuoteIndent += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void decrementBlockQuoteIndent() {
|
||||||
|
blockQuoteIndent -= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void blockQuoteIntent(int blockQuoteIndent) {
|
||||||
|
this.blockQuoteIndent = blockQuoteIndent;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int blockQuoteIndent() {
|
||||||
|
return blockQuoteIndent;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void incrementListLevel() {
|
||||||
|
listLevel += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void decrementListLevel() {
|
||||||
|
listLevel -= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int listLevel() {
|
||||||
|
return listLevel;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void ensureNewLine() {
|
||||||
|
if (builder.length() > 0
|
||||||
|
&& '\n' != builder.lastChar()) {
|
||||||
|
builder.append('\n');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void forceNewLine() {
|
||||||
|
builder.append('\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int length() {
|
||||||
|
return builder.length();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setSpans(int start, @Nullable Object spans) {
|
||||||
|
SpannableBuilder.setSpans(builder, spans, start, builder.length());
|
||||||
|
}
|
||||||
|
|
||||||
|
static class BuilderImpl implements Builder {
|
||||||
|
|
||||||
|
private final Map<Class<? extends Node>, NodeVisitor<? extends Node>> nodes =
|
||||||
|
new HashMap<>(3);
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@Override
|
||||||
|
public <N extends Node> Builder on(@NonNull Class<N> node, @NonNull NodeVisitor<N> nodeVisitor) {
|
||||||
|
nodes.put(node, nodeVisitor);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@Override
|
||||||
|
public MarkwonVisitor build(@NonNull MarkwonTheme theme, @NonNull MarkwonConfiguration configuration) {
|
||||||
|
return new MarkwonVisitorImpl(
|
||||||
|
theme,
|
||||||
|
configuration,
|
||||||
|
Collections.unmodifiableMap(nodes));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -208,7 +208,7 @@ public class SpannableBuilder implements Appendable, CharSequence {
|
|||||||
/**
|
/**
|
||||||
* This method will return all {@link Span} spans that <em>overlap</em> specified range,
|
* This method will return all {@link Span} spans that <em>overlap</em> specified range,
|
||||||
* so if for example a 1..9 range is specified some spans might have 0..6 or 0..10 start/end ranges.
|
* so if for example a 1..9 range is specified some spans might have 0..6 or 0..10 start/end ranges.
|
||||||
* NB spans are returned in reversed order (no in order that we store them internally)
|
* NB spans are returned in reversed order (not in order that we store them internally)
|
||||||
*
|
*
|
||||||
* @since 2.0.1
|
* @since 2.0.1
|
||||||
*/
|
*/
|
||||||
|
@ -9,7 +9,7 @@ import ru.noties.markwon.renderer.ImageSize;
|
|||||||
import ru.noties.markwon.renderer.ImageSizeResolver;
|
import ru.noties.markwon.renderer.ImageSizeResolver;
|
||||||
import ru.noties.markwon.spans.AsyncDrawable;
|
import ru.noties.markwon.spans.AsyncDrawable;
|
||||||
import ru.noties.markwon.spans.LinkSpan;
|
import ru.noties.markwon.spans.LinkSpan;
|
||||||
import ru.noties.markwon.spans.SpannableTheme;
|
import ru.noties.markwon.spans.MarkwonTheme;
|
||||||
import ru.noties.markwon.spans.TableRowSpan;
|
import ru.noties.markwon.spans.TableRowSpan;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -26,32 +26,32 @@ public interface SpannableFactory {
|
|||||||
Object emphasis();
|
Object emphasis();
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
Object blockQuote(@NonNull SpannableTheme theme);
|
Object blockQuote(@NonNull MarkwonTheme theme);
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
Object code(@NonNull SpannableTheme theme, boolean multiline);
|
Object code(@NonNull MarkwonTheme theme, boolean multiline);
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
Object orderedListItem(@NonNull SpannableTheme theme, int startNumber);
|
Object orderedListItem(@NonNull MarkwonTheme theme, int startNumber);
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
Object bulletListItem(@NonNull SpannableTheme theme, int level);
|
Object bulletListItem(@NonNull MarkwonTheme theme, int level);
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
Object thematicBreak(@NonNull SpannableTheme theme);
|
Object thematicBreak(@NonNull MarkwonTheme theme);
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
Object heading(@NonNull SpannableTheme theme, int level);
|
Object heading(@NonNull MarkwonTheme theme, int level);
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
Object strikethrough();
|
Object strikethrough();
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
Object taskListItem(@NonNull SpannableTheme theme, int blockIndent, boolean isDone);
|
Object taskListItem(@NonNull MarkwonTheme theme, int blockIndent, boolean isDone);
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
Object tableRow(
|
Object tableRow(
|
||||||
@NonNull SpannableTheme theme,
|
@NonNull MarkwonTheme theme,
|
||||||
@NonNull List<TableRowSpan.Cell> cells,
|
@NonNull List<TableRowSpan.Cell> cells,
|
||||||
boolean isHeader,
|
boolean isHeader,
|
||||||
boolean isOdd);
|
boolean isOdd);
|
||||||
@ -64,7 +64,7 @@ public interface SpannableFactory {
|
|||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
Object image(
|
Object image(
|
||||||
@NonNull SpannableTheme theme,
|
@NonNull MarkwonTheme theme,
|
||||||
@NonNull String destination,
|
@NonNull String destination,
|
||||||
@NonNull AsyncDrawable.Loader loader,
|
@NonNull AsyncDrawable.Loader loader,
|
||||||
@NonNull ImageSizeResolver imageSizeResolver,
|
@NonNull ImageSizeResolver imageSizeResolver,
|
||||||
@ -73,17 +73,17 @@ public interface SpannableFactory {
|
|||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
Object link(
|
Object link(
|
||||||
@NonNull SpannableTheme theme,
|
@NonNull MarkwonTheme theme,
|
||||||
@NonNull String destination,
|
@NonNull String destination,
|
||||||
@NonNull LinkSpan.Resolver resolver);
|
@NonNull LinkSpan.Resolver resolver);
|
||||||
|
|
||||||
// Currently used by HTML parser
|
// Currently used by HTML parser
|
||||||
@Nullable
|
@Nullable
|
||||||
Object superScript(@NonNull SpannableTheme theme);
|
Object superScript(@NonNull MarkwonTheme theme);
|
||||||
|
|
||||||
// Currently used by HTML parser
|
// Currently used by HTML parser
|
||||||
@Nullable
|
@Nullable
|
||||||
Object subScript(@NonNull SpannableTheme theme);
|
Object subScript(@NonNull MarkwonTheme theme);
|
||||||
|
|
||||||
// Currently used by HTML parser
|
// Currently used by HTML parser
|
||||||
@Nullable
|
@Nullable
|
||||||
|
@ -18,12 +18,12 @@ import ru.noties.markwon.spans.EmphasisSpan;
|
|||||||
import ru.noties.markwon.spans.HeadingSpan;
|
import ru.noties.markwon.spans.HeadingSpan;
|
||||||
import ru.noties.markwon.spans.LinkSpan;
|
import ru.noties.markwon.spans.LinkSpan;
|
||||||
import ru.noties.markwon.spans.OrderedListItemSpan;
|
import ru.noties.markwon.spans.OrderedListItemSpan;
|
||||||
import ru.noties.markwon.spans.SpannableTheme;
|
import ru.noties.markwon.spans.MarkwonTheme;
|
||||||
import ru.noties.markwon.spans.StrongEmphasisSpan;
|
import ru.noties.markwon.spans.StrongEmphasisSpan;
|
||||||
import ru.noties.markwon.spans.SubScriptSpan;
|
import ru.noties.markwon.spans.SubScriptSpan;
|
||||||
import ru.noties.markwon.spans.SuperScriptSpan;
|
import ru.noties.markwon.spans.SuperScriptSpan;
|
||||||
import ru.noties.markwon.spans.TableRowSpan;
|
import ru.noties.markwon.spans.TableRowSpan;
|
||||||
import ru.noties.markwon.spans.TaskListSpan;
|
import ru.noties.markwon.tasklist.TaskListSpan;
|
||||||
import ru.noties.markwon.spans.ThematicBreakSpan;
|
import ru.noties.markwon.spans.ThematicBreakSpan;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -50,38 +50,38 @@ public class SpannableFactoryDef implements SpannableFactory {
|
|||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
public Object blockQuote(@NonNull SpannableTheme theme) {
|
public Object blockQuote(@NonNull MarkwonTheme theme) {
|
||||||
return new BlockQuoteSpan(theme);
|
return new BlockQuoteSpan(theme);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
public Object code(@NonNull SpannableTheme theme, boolean multiline) {
|
public Object code(@NonNull MarkwonTheme theme, boolean multiline) {
|
||||||
return new CodeSpan(theme, multiline);
|
return new CodeSpan(theme, multiline);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
public Object orderedListItem(@NonNull SpannableTheme theme, int startNumber) {
|
public Object orderedListItem(@NonNull MarkwonTheme theme, int startNumber) {
|
||||||
// todo| in order to provide real RTL experience there must be a way to provide this string
|
// todo| in order to provide real RTL experience there must be a way to provide this string
|
||||||
return new OrderedListItemSpan(theme, String.valueOf(startNumber) + "." + '\u00a0');
|
return new OrderedListItemSpan(theme, String.valueOf(startNumber) + "." + '\u00a0');
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
public Object bulletListItem(@NonNull SpannableTheme theme, int level) {
|
public Object bulletListItem(@NonNull MarkwonTheme theme, int level) {
|
||||||
return new BulletListItemSpan(theme, level);
|
return new BulletListItemSpan(theme, level);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
public Object thematicBreak(@NonNull SpannableTheme theme) {
|
public Object thematicBreak(@NonNull MarkwonTheme theme) {
|
||||||
return new ThematicBreakSpan(theme);
|
return new ThematicBreakSpan(theme);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
public Object heading(@NonNull SpannableTheme theme, int level) {
|
public Object heading(@NonNull MarkwonTheme theme, int level) {
|
||||||
return new HeadingSpan(theme, level);
|
return new HeadingSpan(theme, level);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -93,13 +93,13 @@ public class SpannableFactoryDef implements SpannableFactory {
|
|||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
public Object taskListItem(@NonNull SpannableTheme theme, int blockIndent, boolean isDone) {
|
public Object taskListItem(@NonNull MarkwonTheme theme, int blockIndent, boolean isDone) {
|
||||||
return new TaskListSpan(theme, blockIndent, isDone);
|
return new TaskListSpan(theme, blockIndent, isDone);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
public Object tableRow(@NonNull SpannableTheme theme, @NonNull List<TableRowSpan.Cell> cells, boolean isHeader, boolean isOdd) {
|
public Object tableRow(@NonNull MarkwonTheme theme, @NonNull List<TableRowSpan.Cell> cells, boolean isHeader, boolean isOdd) {
|
||||||
return new TableRowSpan(theme, cells, isHeader, isOdd);
|
return new TableRowSpan(theme, cells, isHeader, isOdd);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -114,7 +114,7 @@ public class SpannableFactoryDef implements SpannableFactory {
|
|||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
public Object image(@NonNull SpannableTheme theme, @NonNull String destination, @NonNull AsyncDrawable.Loader loader, @NonNull ImageSizeResolver imageSizeResolver, @Nullable ImageSize imageSize, boolean replacementTextIsLink) {
|
public Object image(@NonNull MarkwonTheme theme, @NonNull String destination, @NonNull AsyncDrawable.Loader loader, @NonNull ImageSizeResolver imageSizeResolver, @Nullable ImageSize imageSize, boolean replacementTextIsLink) {
|
||||||
return new AsyncDrawableSpan(
|
return new AsyncDrawableSpan(
|
||||||
theme,
|
theme,
|
||||||
new AsyncDrawable(
|
new AsyncDrawable(
|
||||||
@ -130,18 +130,18 @@ public class SpannableFactoryDef implements SpannableFactory {
|
|||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
public Object link(@NonNull SpannableTheme theme, @NonNull String destination, @NonNull LinkSpan.Resolver resolver) {
|
public Object link(@NonNull MarkwonTheme theme, @NonNull String destination, @NonNull LinkSpan.Resolver resolver) {
|
||||||
return new LinkSpan(theme, destination, resolver);
|
return new LinkSpan(theme, destination, resolver);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
public Object superScript(@NonNull SpannableTheme theme) {
|
public Object superScript(@NonNull MarkwonTheme theme) {
|
||||||
return new SuperScriptSpan(theme);
|
return new SuperScriptSpan(theme);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object subScript(@NonNull SpannableTheme theme) {
|
public Object subScript(@NonNull MarkwonTheme theme) {
|
||||||
return new SubScriptSpan(theme);
|
return new SubScriptSpan(theme);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
268
markwon/src/main/java/ru/noties/markwon/core/CorePlugin.java
Normal file
268
markwon/src/main/java/ru/noties/markwon/core/CorePlugin.java
Normal file
@ -0,0 +1,268 @@
|
|||||||
|
package ru.noties.markwon.core;
|
||||||
|
|
||||||
|
import android.support.annotation.NonNull;
|
||||||
|
import android.support.annotation.Nullable;
|
||||||
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import org.commonmark.node.BlockQuote;
|
||||||
|
import org.commonmark.node.BulletList;
|
||||||
|
import org.commonmark.node.Code;
|
||||||
|
import org.commonmark.node.Emphasis;
|
||||||
|
import org.commonmark.node.FencedCodeBlock;
|
||||||
|
import org.commonmark.node.IndentedCodeBlock;
|
||||||
|
import org.commonmark.node.ListItem;
|
||||||
|
import org.commonmark.node.Node;
|
||||||
|
import org.commonmark.node.OrderedList;
|
||||||
|
import org.commonmark.node.StrongEmphasis;
|
||||||
|
import org.commonmark.node.Text;
|
||||||
|
import org.commonmark.node.ThematicBreak;
|
||||||
|
|
||||||
|
import ru.noties.markwon.AbstractMarkwonPlugin;
|
||||||
|
import ru.noties.markwon.MarkwonVisitor;
|
||||||
|
import ru.noties.markwon.SpannableBuilder;
|
||||||
|
import ru.noties.markwon.spans.OrderedListItemSpan;
|
||||||
|
|
||||||
|
public class CorePlugin extends AbstractMarkwonPlugin {
|
||||||
|
|
||||||
|
// todo: factory. Logically it must be here only, but in order to make spans
|
||||||
|
// uniform in HTML (for example) we should expose it... Anyway, this factory _must_
|
||||||
|
// include only _core_ spans
|
||||||
|
|
||||||
|
// todo: softBreak adds new line should be here (or maybe removed even?)
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void configureVisitor(@NonNull MarkwonVisitor.Builder builder) {
|
||||||
|
text(builder);
|
||||||
|
strongEmphasis(builder);
|
||||||
|
emphasis(builder);
|
||||||
|
blockQuote(builder);
|
||||||
|
code(builder);
|
||||||
|
fencedCodeBlock(builder);
|
||||||
|
indentedCodeBlock(builder);
|
||||||
|
bulletList(builder);
|
||||||
|
orderedList(builder);
|
||||||
|
listItem(builder);
|
||||||
|
thematicBreak(builder);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void beforeSetText(@NonNull TextView textView, @NonNull SpannableBuilder builder) {
|
||||||
|
OrderedListItemSpan.measure(textView, builder);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void text(@NonNull MarkwonVisitor.Builder builder) {
|
||||||
|
builder.on(Text.class, new MarkwonVisitor.NodeVisitor<Text>() {
|
||||||
|
@Override
|
||||||
|
public void visit(@NonNull MarkwonVisitor visitor, @NonNull Text text) {
|
||||||
|
visitor.builder().append(text.getLiteral());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void strongEmphasis(@NonNull MarkwonVisitor.Builder builder) {
|
||||||
|
builder.on(StrongEmphasis.class, new MarkwonVisitor.NodeVisitor<StrongEmphasis>() {
|
||||||
|
@Override
|
||||||
|
public void visit(@NonNull MarkwonVisitor visitor, @NonNull StrongEmphasis strongEmphasis) {
|
||||||
|
final int length = visitor.length();
|
||||||
|
visitor.visitChildren(strongEmphasis);
|
||||||
|
visitor.setSpans(length, visitor.configuration().factory().strongEmphasis());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void emphasis(@NonNull MarkwonVisitor.Builder builder) {
|
||||||
|
builder.on(Emphasis.class, new MarkwonVisitor.NodeVisitor<Emphasis>() {
|
||||||
|
@Override
|
||||||
|
public void visit(@NonNull MarkwonVisitor visitor, @NonNull Emphasis emphasis) {
|
||||||
|
final int length = visitor.length();
|
||||||
|
visitor.visitChildren(emphasis);
|
||||||
|
visitor.setSpans(length, visitor.configuration().factory().emphasis());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void blockQuote(@NonNull MarkwonVisitor.Builder builder) {
|
||||||
|
builder.on(BlockQuote.class, new MarkwonVisitor.NodeVisitor<BlockQuote>() {
|
||||||
|
@Override
|
||||||
|
public void visit(@NonNull MarkwonVisitor visitor, @NonNull BlockQuote blockQuote) {
|
||||||
|
|
||||||
|
visitor.ensureNewLine();
|
||||||
|
|
||||||
|
if (visitor.blockQuoteIndent() > 0) {
|
||||||
|
visitor.forceNewLine();
|
||||||
|
}
|
||||||
|
|
||||||
|
final int length = visitor.length();
|
||||||
|
visitor.incrementBlockQuoteIndent();
|
||||||
|
visitor.visitChildren(blockQuote);
|
||||||
|
visitor.setSpans(length, visitor.configuration().factory().blockQuote(visitor.theme()));
|
||||||
|
visitor.decrementBlockQuoteIndent();
|
||||||
|
|
||||||
|
if (visitor.hasNext(blockQuote)) {
|
||||||
|
visitor.ensureNewLine();
|
||||||
|
if (visitor.blockQuoteIndent() > 0) {
|
||||||
|
visitor.forceNewLine();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void code(@NonNull MarkwonVisitor.Builder builder) {
|
||||||
|
builder.on(Code.class, new MarkwonVisitor.NodeVisitor<Code>() {
|
||||||
|
@Override
|
||||||
|
public void visit(@NonNull MarkwonVisitor visitor, @NonNull Code code) {
|
||||||
|
|
||||||
|
final int length = visitor.length();
|
||||||
|
|
||||||
|
// NB, in order to provide a _padding_ feeling code is wrapped inside two unbreakable spaces
|
||||||
|
// unfortunately we cannot use this for multiline code as we cannot control where a new line break will be inserted
|
||||||
|
visitor.builder()
|
||||||
|
.append('\u00a0')
|
||||||
|
.append(code.getLiteral())
|
||||||
|
.append('\u00a0');
|
||||||
|
|
||||||
|
visitor.setSpans(length, visitor.configuration().factory().code(visitor.theme(), false));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void fencedCodeBlock(@NonNull MarkwonVisitor.Builder builder) {
|
||||||
|
builder.on(FencedCodeBlock.class, new MarkwonVisitor.NodeVisitor<FencedCodeBlock>() {
|
||||||
|
@Override
|
||||||
|
public void visit(@NonNull MarkwonVisitor visitor, @NonNull FencedCodeBlock fencedCodeBlock) {
|
||||||
|
visitCodeBlock(visitor, fencedCodeBlock.getInfo(), fencedCodeBlock.getLiteral(), fencedCodeBlock);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void indentedCodeBlock(@NonNull MarkwonVisitor.Builder builder) {
|
||||||
|
builder.on(IndentedCodeBlock.class, new MarkwonVisitor.NodeVisitor<IndentedCodeBlock>() {
|
||||||
|
@Override
|
||||||
|
public void visit(@NonNull MarkwonVisitor visitor, @NonNull IndentedCodeBlock indentedCodeBlock) {
|
||||||
|
visitCodeBlock(visitor, null, indentedCodeBlock.getLiteral(), indentedCodeBlock);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void visitCodeBlock(
|
||||||
|
@NonNull MarkwonVisitor visitor,
|
||||||
|
@Nullable String info,
|
||||||
|
@NonNull String code,
|
||||||
|
@NonNull Node node) {
|
||||||
|
|
||||||
|
visitor.ensureNewLine();
|
||||||
|
|
||||||
|
final int length = visitor.length();
|
||||||
|
|
||||||
|
visitor.builder()
|
||||||
|
.append('\u00a0').append('\n')
|
||||||
|
.append(visitor.configuration().syntaxHighlight().highlight(info, code));
|
||||||
|
|
||||||
|
visitor.ensureNewLine();
|
||||||
|
|
||||||
|
visitor.builder().append('\u00a0');
|
||||||
|
|
||||||
|
visitor.setSpans(length, visitor.configuration().factory().code(visitor.theme(), true));
|
||||||
|
|
||||||
|
if (visitor.hasNext(node)) {
|
||||||
|
visitor.ensureNewLine();
|
||||||
|
visitor.forceNewLine();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void bulletList(@NonNull MarkwonVisitor.Builder builder) {
|
||||||
|
builder.on(BulletList.class, new MarkwonVisitor.NodeVisitor<BulletList>() {
|
||||||
|
@Override
|
||||||
|
public void visit(@NonNull MarkwonVisitor visitor, @NonNull BulletList bulletList) {
|
||||||
|
visitList(visitor, bulletList);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void orderedList(@NonNull MarkwonVisitor.Builder builder) {
|
||||||
|
builder.on(OrderedList.class, new MarkwonVisitor.NodeVisitor<OrderedList>() {
|
||||||
|
@Override
|
||||||
|
public void visit(@NonNull MarkwonVisitor visitor, @NonNull OrderedList orderedList) {
|
||||||
|
visitList(visitor, orderedList);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void visitList(@NonNull MarkwonVisitor visitor, @NonNull Node node) {
|
||||||
|
|
||||||
|
visitor.ensureNewLine();
|
||||||
|
|
||||||
|
visitor.visitChildren(node);
|
||||||
|
|
||||||
|
if (visitor.hasNext(node)) {
|
||||||
|
visitor.ensureNewLine();
|
||||||
|
if (visitor.listLevel() == 0
|
||||||
|
&& visitor.blockQuoteIndent() == 0) {
|
||||||
|
visitor.forceNewLine();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void listItem(@NonNull MarkwonVisitor.Builder builder) {
|
||||||
|
builder.on(ListItem.class, new MarkwonVisitor.NodeVisitor<ListItem>() {
|
||||||
|
@Override
|
||||||
|
public void visit(@NonNull MarkwonVisitor visitor, @NonNull ListItem listItem) {
|
||||||
|
|
||||||
|
final int length = visitor.length();
|
||||||
|
|
||||||
|
visitor.incrementBlockQuoteIndent();
|
||||||
|
visitor.incrementListLevel();
|
||||||
|
|
||||||
|
final Node parent = listItem.getParent();
|
||||||
|
if (parent instanceof OrderedList) {
|
||||||
|
|
||||||
|
final int start = ((OrderedList) parent).getStartNumber();
|
||||||
|
|
||||||
|
visitor.visitChildren(listItem);
|
||||||
|
visitor.setSpans(length, visitor.configuration().factory().orderedListItem(visitor.theme(), start));
|
||||||
|
|
||||||
|
|
||||||
|
// after we have visited the children increment start number
|
||||||
|
final OrderedList orderedList = (OrderedList) parent;
|
||||||
|
orderedList.setStartNumber(orderedList.getStartNumber() + 1);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
visitor.visitChildren(listItem);
|
||||||
|
visitor.setSpans(length, visitor.configuration().factory().bulletListItem(visitor.theme(), visitor.listLevel() - 1));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
visitor.decrementBlockQuoteIndent();
|
||||||
|
visitor.decrementListLevel();
|
||||||
|
|
||||||
|
if (visitor.hasNext(listItem)) {
|
||||||
|
visitor.ensureNewLine();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void thematicBreak(@NonNull MarkwonVisitor.Builder builder) {
|
||||||
|
builder.on(ThematicBreak.class, new MarkwonVisitor.NodeVisitor<ThematicBreak>() {
|
||||||
|
@Override
|
||||||
|
public void visit(@NonNull MarkwonVisitor visitor, @NonNull ThematicBreak thematicBreak) {
|
||||||
|
|
||||||
|
visitor.ensureNewLine();
|
||||||
|
|
||||||
|
final int length = visitor.length();
|
||||||
|
|
||||||
|
// without space it won't render
|
||||||
|
visitor.builder().append('\u00a0');
|
||||||
|
|
||||||
|
visitor.setSpans(length, visitor.configuration().factory().thematicBreak(visitor.theme()));
|
||||||
|
|
||||||
|
if (visitor.hasNext(thematicBreak)) {
|
||||||
|
visitor.ensureNewLine();
|
||||||
|
visitor.forceNewLine();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@ -38,10 +38,10 @@ import java.util.ArrayList;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import ru.noties.markwon.SpannableBuilder;
|
import ru.noties.markwon.SpannableBuilder;
|
||||||
import ru.noties.markwon.SpannableConfiguration;
|
import ru.noties.markwon.MarkwonConfiguration;
|
||||||
import ru.noties.markwon.SpannableFactory;
|
import ru.noties.markwon.SpannableFactory;
|
||||||
import ru.noties.markwon.html.api.MarkwonHtmlParser;
|
import ru.noties.markwon.html.api.MarkwonHtmlParser;
|
||||||
import ru.noties.markwon.spans.SpannableTheme;
|
import ru.noties.markwon.spans.MarkwonTheme;
|
||||||
import ru.noties.markwon.spans.TableRowSpan;
|
import ru.noties.markwon.spans.TableRowSpan;
|
||||||
import ru.noties.markwon.tasklist.TaskListBlock;
|
import ru.noties.markwon.tasklist.TaskListBlock;
|
||||||
import ru.noties.markwon.tasklist.TaskListItem;
|
import ru.noties.markwon.tasklist.TaskListItem;
|
||||||
@ -49,11 +49,11 @@ import ru.noties.markwon.tasklist.TaskListItem;
|
|||||||
@SuppressWarnings("WeakerAccess")
|
@SuppressWarnings("WeakerAccess")
|
||||||
public class SpannableMarkdownVisitor extends AbstractVisitor {
|
public class SpannableMarkdownVisitor extends AbstractVisitor {
|
||||||
|
|
||||||
private final SpannableConfiguration configuration;
|
private final MarkwonConfiguration configuration;
|
||||||
private final SpannableBuilder builder;
|
private final SpannableBuilder builder;
|
||||||
private final MarkwonHtmlParser htmlParser;
|
private final MarkwonHtmlParser htmlParser;
|
||||||
|
|
||||||
private final SpannableTheme theme;
|
private final MarkwonTheme theme;
|
||||||
private final SpannableFactory factory;
|
private final SpannableFactory factory;
|
||||||
|
|
||||||
private int blockQuoteIndent;
|
private int blockQuoteIndent;
|
||||||
@ -64,7 +64,7 @@ public class SpannableMarkdownVisitor extends AbstractVisitor {
|
|||||||
private int tableRows;
|
private int tableRows;
|
||||||
|
|
||||||
public SpannableMarkdownVisitor(
|
public SpannableMarkdownVisitor(
|
||||||
@NonNull SpannableConfiguration configuration,
|
@NonNull MarkwonConfiguration configuration,
|
||||||
@NonNull SpannableBuilder builder
|
@NonNull SpannableBuilder builder
|
||||||
) {
|
) {
|
||||||
this.configuration = configuration;
|
this.configuration = configuration;
|
||||||
|
@ -4,13 +4,13 @@ import android.support.annotation.NonNull;
|
|||||||
|
|
||||||
import org.commonmark.node.Node;
|
import org.commonmark.node.Node;
|
||||||
|
|
||||||
|
import ru.noties.markwon.MarkwonConfiguration;
|
||||||
import ru.noties.markwon.SpannableBuilder;
|
import ru.noties.markwon.SpannableBuilder;
|
||||||
import ru.noties.markwon.SpannableConfiguration;
|
|
||||||
|
|
||||||
public class SpannableRenderer {
|
public class SpannableRenderer {
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
public CharSequence render(@NonNull SpannableConfiguration configuration, @NonNull Node node) {
|
public CharSequence render(@NonNull MarkwonConfiguration configuration, @NonNull Node node) {
|
||||||
final SpannableBuilder builder = new SpannableBuilder();
|
final SpannableBuilder builder = new SpannableBuilder();
|
||||||
node.accept(new SpannableMarkdownVisitor(configuration, builder));
|
node.accept(new SpannableMarkdownVisitor(configuration, builder));
|
||||||
return builder.text();
|
return builder.text();
|
||||||
|
@ -9,7 +9,7 @@ import java.util.Locale;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import ru.noties.markwon.SpannableBuilder;
|
import ru.noties.markwon.SpannableBuilder;
|
||||||
import ru.noties.markwon.SpannableConfiguration;
|
import ru.noties.markwon.MarkwonConfiguration;
|
||||||
import ru.noties.markwon.html.api.MarkwonHtmlParser;
|
import ru.noties.markwon.html.api.MarkwonHtmlParser;
|
||||||
import ru.noties.markwon.renderer.html2.tag.BlockquoteHandler;
|
import ru.noties.markwon.renderer.html2.tag.BlockquoteHandler;
|
||||||
import ru.noties.markwon.renderer.html2.tag.EmphasisHandler;
|
import ru.noties.markwon.renderer.html2.tag.EmphasisHandler;
|
||||||
@ -30,7 +30,7 @@ import ru.noties.markwon.renderer.html2.tag.UnderlineHandler;
|
|||||||
public abstract class MarkwonHtmlRenderer {
|
public abstract class MarkwonHtmlRenderer {
|
||||||
|
|
||||||
public abstract void render(
|
public abstract void render(
|
||||||
@NonNull SpannableConfiguration configuration,
|
@NonNull MarkwonConfiguration configuration,
|
||||||
@NonNull SpannableBuilder builder,
|
@NonNull SpannableBuilder builder,
|
||||||
@NonNull MarkwonHtmlParser parser
|
@NonNull MarkwonHtmlParser parser
|
||||||
);
|
);
|
||||||
|
@ -7,7 +7,7 @@ import java.util.List;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import ru.noties.markwon.SpannableBuilder;
|
import ru.noties.markwon.SpannableBuilder;
|
||||||
import ru.noties.markwon.SpannableConfiguration;
|
import ru.noties.markwon.MarkwonConfiguration;
|
||||||
import ru.noties.markwon.html.api.HtmlTag;
|
import ru.noties.markwon.html.api.HtmlTag;
|
||||||
import ru.noties.markwon.html.api.MarkwonHtmlParser;
|
import ru.noties.markwon.html.api.MarkwonHtmlParser;
|
||||||
import ru.noties.markwon.renderer.html2.tag.TagHandler;
|
import ru.noties.markwon.renderer.html2.tag.TagHandler;
|
||||||
@ -22,7 +22,7 @@ class MarkwonHtmlRendererImpl extends MarkwonHtmlRenderer {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void render(
|
public void render(
|
||||||
@NonNull final SpannableConfiguration configuration,
|
@NonNull final MarkwonConfiguration configuration,
|
||||||
@NonNull final SpannableBuilder builder,
|
@NonNull final SpannableBuilder builder,
|
||||||
@NonNull MarkwonHtmlParser parser) {
|
@NonNull MarkwonHtmlParser parser) {
|
||||||
|
|
||||||
|
@ -3,14 +3,14 @@ package ru.noties.markwon.renderer.html2.tag;
|
|||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
|
|
||||||
import ru.noties.markwon.SpannableBuilder;
|
import ru.noties.markwon.SpannableBuilder;
|
||||||
import ru.noties.markwon.SpannableConfiguration;
|
import ru.noties.markwon.MarkwonConfiguration;
|
||||||
import ru.noties.markwon.html.api.HtmlTag;
|
import ru.noties.markwon.html.api.HtmlTag;
|
||||||
|
|
||||||
public class BlockquoteHandler extends TagHandler {
|
public class BlockquoteHandler extends TagHandler {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void handle(
|
public void handle(
|
||||||
@NonNull SpannableConfiguration configuration,
|
@NonNull MarkwonConfiguration configuration,
|
||||||
@NonNull SpannableBuilder builder,
|
@NonNull SpannableBuilder builder,
|
||||||
@NonNull HtmlTag tag) {
|
@NonNull HtmlTag tag) {
|
||||||
|
|
||||||
|
@ -3,13 +3,13 @@ package ru.noties.markwon.renderer.html2.tag;
|
|||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
|
|
||||||
import ru.noties.markwon.SpannableConfiguration;
|
import ru.noties.markwon.MarkwonConfiguration;
|
||||||
import ru.noties.markwon.html.api.HtmlTag;
|
import ru.noties.markwon.html.api.HtmlTag;
|
||||||
|
|
||||||
public class EmphasisHandler extends SimpleTagHandler {
|
public class EmphasisHandler extends SimpleTagHandler {
|
||||||
@Nullable
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
public Object getSpans(@NonNull SpannableConfiguration configuration, @NonNull HtmlTag tag) {
|
public Object getSpans(@NonNull MarkwonConfiguration configuration, @NonNull HtmlTag tag) {
|
||||||
return configuration.factory().emphasis();
|
return configuration.factory().emphasis();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,7 @@ package ru.noties.markwon.renderer.html2.tag;
|
|||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
|
|
||||||
import ru.noties.markwon.SpannableConfiguration;
|
import ru.noties.markwon.MarkwonConfiguration;
|
||||||
import ru.noties.markwon.html.api.HtmlTag;
|
import ru.noties.markwon.html.api.HtmlTag;
|
||||||
|
|
||||||
public class HeadingHandler extends SimpleTagHandler {
|
public class HeadingHandler extends SimpleTagHandler {
|
||||||
@ -16,7 +16,7 @@ public class HeadingHandler extends SimpleTagHandler {
|
|||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
public Object getSpans(@NonNull SpannableConfiguration configuration, @NonNull HtmlTag tag) {
|
public Object getSpans(@NonNull MarkwonConfiguration configuration, @NonNull HtmlTag tag) {
|
||||||
return configuration.factory().heading(configuration.theme(), level);
|
return configuration.factory().heading(configuration.theme(), level);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,7 @@ import android.text.TextUtils;
|
|||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import ru.noties.markwon.SpannableConfiguration;
|
import ru.noties.markwon.MarkwonConfiguration;
|
||||||
import ru.noties.markwon.html.api.HtmlTag;
|
import ru.noties.markwon.html.api.HtmlTag;
|
||||||
import ru.noties.markwon.renderer.ImageSize;
|
import ru.noties.markwon.renderer.ImageSize;
|
||||||
import ru.noties.markwon.renderer.html2.CssInlineStyleParser;
|
import ru.noties.markwon.renderer.html2.CssInlineStyleParser;
|
||||||
@ -31,7 +31,7 @@ public class ImageHandler extends SimpleTagHandler {
|
|||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
public Object getSpans(@NonNull SpannableConfiguration configuration, @NonNull HtmlTag tag) {
|
public Object getSpans(@NonNull MarkwonConfiguration configuration, @NonNull HtmlTag tag) {
|
||||||
|
|
||||||
final Map<String, String> attributes = tag.attributes();
|
final Map<String, String> attributes = tag.attributes();
|
||||||
final String src = attributes.get("src");
|
final String src = attributes.get("src");
|
||||||
|
@ -4,13 +4,13 @@ import android.support.annotation.NonNull;
|
|||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
|
|
||||||
import ru.noties.markwon.SpannableConfiguration;
|
import ru.noties.markwon.MarkwonConfiguration;
|
||||||
import ru.noties.markwon.html.api.HtmlTag;
|
import ru.noties.markwon.html.api.HtmlTag;
|
||||||
|
|
||||||
public class LinkHandler extends SimpleTagHandler {
|
public class LinkHandler extends SimpleTagHandler {
|
||||||
@Nullable
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
public Object getSpans(@NonNull SpannableConfiguration configuration, @NonNull HtmlTag tag) {
|
public Object getSpans(@NonNull MarkwonConfiguration configuration, @NonNull HtmlTag tag) {
|
||||||
final String destination = tag.attributes().get("href");
|
final String destination = tag.attributes().get("href");
|
||||||
if (!TextUtils.isEmpty(destination)) {
|
if (!TextUtils.isEmpty(destination)) {
|
||||||
return configuration.factory().link(
|
return configuration.factory().link(
|
||||||
|
@ -2,15 +2,15 @@ package ru.noties.markwon.renderer.html2.tag;
|
|||||||
|
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
|
|
||||||
|
import ru.noties.markwon.MarkwonConfiguration;
|
||||||
import ru.noties.markwon.SpannableBuilder;
|
import ru.noties.markwon.SpannableBuilder;
|
||||||
import ru.noties.markwon.SpannableConfiguration;
|
|
||||||
import ru.noties.markwon.html.api.HtmlTag;
|
import ru.noties.markwon.html.api.HtmlTag;
|
||||||
|
|
||||||
public class ListHandler extends TagHandler {
|
public class ListHandler extends TagHandler {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void handle(
|
public void handle(
|
||||||
@NonNull SpannableConfiguration configuration,
|
@NonNull MarkwonConfiguration configuration,
|
||||||
@NonNull SpannableBuilder builder,
|
@NonNull SpannableBuilder builder,
|
||||||
@NonNull HtmlTag tag) {
|
@NonNull HtmlTag tag) {
|
||||||
|
|
||||||
|
@ -4,16 +4,16 @@ import android.support.annotation.NonNull;
|
|||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
|
|
||||||
import ru.noties.markwon.SpannableBuilder;
|
import ru.noties.markwon.SpannableBuilder;
|
||||||
import ru.noties.markwon.SpannableConfiguration;
|
import ru.noties.markwon.MarkwonConfiguration;
|
||||||
import ru.noties.markwon.html.api.HtmlTag;
|
import ru.noties.markwon.html.api.HtmlTag;
|
||||||
|
|
||||||
public abstract class SimpleTagHandler extends TagHandler {
|
public abstract class SimpleTagHandler extends TagHandler {
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
public abstract Object getSpans(@NonNull SpannableConfiguration configuration, @NonNull HtmlTag tag);
|
public abstract Object getSpans(@NonNull MarkwonConfiguration configuration, @NonNull HtmlTag tag);
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void handle(@NonNull SpannableConfiguration configuration, @NonNull SpannableBuilder builder, @NonNull HtmlTag tag) {
|
public void handle(@NonNull MarkwonConfiguration configuration, @NonNull SpannableBuilder builder, @NonNull HtmlTag tag) {
|
||||||
final Object spans = getSpans(configuration, tag);
|
final Object spans = getSpans(configuration, tag);
|
||||||
if (spans != null) {
|
if (spans != null) {
|
||||||
SpannableBuilder.setSpans(builder, spans, tag.start(), tag.end());
|
SpannableBuilder.setSpans(builder, spans, tag.start(), tag.end());
|
||||||
|
@ -2,15 +2,15 @@ package ru.noties.markwon.renderer.html2.tag;
|
|||||||
|
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
|
|
||||||
|
import ru.noties.markwon.MarkwonConfiguration;
|
||||||
import ru.noties.markwon.SpannableBuilder;
|
import ru.noties.markwon.SpannableBuilder;
|
||||||
import ru.noties.markwon.SpannableConfiguration;
|
|
||||||
import ru.noties.markwon.html.api.HtmlTag;
|
import ru.noties.markwon.html.api.HtmlTag;
|
||||||
|
|
||||||
public class StrikeHandler extends TagHandler {
|
public class StrikeHandler extends TagHandler {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void handle(
|
public void handle(
|
||||||
@NonNull SpannableConfiguration configuration,
|
@NonNull MarkwonConfiguration configuration,
|
||||||
@NonNull SpannableBuilder builder,
|
@NonNull SpannableBuilder builder,
|
||||||
@NonNull HtmlTag tag) {
|
@NonNull HtmlTag tag) {
|
||||||
|
|
||||||
|
@ -3,13 +3,13 @@ package ru.noties.markwon.renderer.html2.tag;
|
|||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
|
|
||||||
import ru.noties.markwon.SpannableConfiguration;
|
import ru.noties.markwon.MarkwonConfiguration;
|
||||||
import ru.noties.markwon.html.api.HtmlTag;
|
import ru.noties.markwon.html.api.HtmlTag;
|
||||||
|
|
||||||
public class StrongEmphasisHandler extends SimpleTagHandler {
|
public class StrongEmphasisHandler extends SimpleTagHandler {
|
||||||
@Nullable
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
public Object getSpans(@NonNull SpannableConfiguration configuration, @NonNull HtmlTag tag) {
|
public Object getSpans(@NonNull MarkwonConfiguration configuration, @NonNull HtmlTag tag) {
|
||||||
return configuration.factory().strongEmphasis();
|
return configuration.factory().strongEmphasis();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,13 +3,13 @@ package ru.noties.markwon.renderer.html2.tag;
|
|||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
|
|
||||||
import ru.noties.markwon.SpannableConfiguration;
|
import ru.noties.markwon.MarkwonConfiguration;
|
||||||
import ru.noties.markwon.html.api.HtmlTag;
|
import ru.noties.markwon.html.api.HtmlTag;
|
||||||
|
|
||||||
public class SubScriptHandler extends SimpleTagHandler {
|
public class SubScriptHandler extends SimpleTagHandler {
|
||||||
@Nullable
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
public Object getSpans(@NonNull SpannableConfiguration configuration, @NonNull HtmlTag tag) {
|
public Object getSpans(@NonNull MarkwonConfiguration configuration, @NonNull HtmlTag tag) {
|
||||||
return configuration.factory().subScript(configuration.theme());
|
return configuration.factory().subScript(configuration.theme());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,13 +3,13 @@ package ru.noties.markwon.renderer.html2.tag;
|
|||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
|
|
||||||
import ru.noties.markwon.SpannableConfiguration;
|
import ru.noties.markwon.MarkwonConfiguration;
|
||||||
import ru.noties.markwon.html.api.HtmlTag;
|
import ru.noties.markwon.html.api.HtmlTag;
|
||||||
|
|
||||||
public class SuperScriptHandler extends SimpleTagHandler {
|
public class SuperScriptHandler extends SimpleTagHandler {
|
||||||
@Nullable
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
public Object getSpans(@NonNull SpannableConfiguration configuration, @NonNull HtmlTag tag) {
|
public Object getSpans(@NonNull MarkwonConfiguration configuration, @NonNull HtmlTag tag) {
|
||||||
return configuration.factory().superScript(configuration.theme());
|
return configuration.factory().superScript(configuration.theme());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,20 +2,20 @@ package ru.noties.markwon.renderer.html2.tag;
|
|||||||
|
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
|
|
||||||
|
import ru.noties.markwon.MarkwonConfiguration;
|
||||||
import ru.noties.markwon.SpannableBuilder;
|
import ru.noties.markwon.SpannableBuilder;
|
||||||
import ru.noties.markwon.SpannableConfiguration;
|
|
||||||
import ru.noties.markwon.html.api.HtmlTag;
|
import ru.noties.markwon.html.api.HtmlTag;
|
||||||
|
|
||||||
public abstract class TagHandler {
|
public abstract class TagHandler {
|
||||||
|
|
||||||
public abstract void handle(
|
public abstract void handle(
|
||||||
@NonNull SpannableConfiguration configuration,
|
@NonNull MarkwonConfiguration configuration,
|
||||||
@NonNull SpannableBuilder builder,
|
@NonNull SpannableBuilder builder,
|
||||||
@NonNull HtmlTag tag
|
@NonNull HtmlTag tag
|
||||||
);
|
);
|
||||||
|
|
||||||
protected static void visitChildren(
|
protected static void visitChildren(
|
||||||
@NonNull SpannableConfiguration configuration,
|
@NonNull MarkwonConfiguration configuration,
|
||||||
@NonNull SpannableBuilder builder,
|
@NonNull SpannableBuilder builder,
|
||||||
@NonNull HtmlTag.Block block) {
|
@NonNull HtmlTag.Block block) {
|
||||||
|
|
||||||
|
@ -3,14 +3,14 @@ package ru.noties.markwon.renderer.html2.tag;
|
|||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
|
|
||||||
import ru.noties.markwon.SpannableBuilder;
|
import ru.noties.markwon.SpannableBuilder;
|
||||||
import ru.noties.markwon.SpannableConfiguration;
|
import ru.noties.markwon.MarkwonConfiguration;
|
||||||
import ru.noties.markwon.html.api.HtmlTag;
|
import ru.noties.markwon.html.api.HtmlTag;
|
||||||
|
|
||||||
public class UnderlineHandler extends TagHandler {
|
public class UnderlineHandler extends TagHandler {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void handle(
|
public void handle(
|
||||||
@NonNull SpannableConfiguration configuration,
|
@NonNull MarkwonConfiguration configuration,
|
||||||
@NonNull SpannableBuilder builder,
|
@NonNull SpannableBuilder builder,
|
||||||
@NonNull HtmlTag tag) {
|
@NonNull HtmlTag tag) {
|
||||||
|
|
||||||
|
@ -24,24 +24,24 @@ public class AsyncDrawableSpan extends ReplacementSpan {
|
|||||||
public static final int ALIGN_BASELINE = 1;
|
public static final int ALIGN_BASELINE = 1;
|
||||||
public static final int ALIGN_CENTER = 2; // will only center if drawable height is less than text line height
|
public static final int ALIGN_CENTER = 2; // will only center if drawable height is less than text line height
|
||||||
|
|
||||||
private final SpannableTheme theme;
|
private final MarkwonTheme theme;
|
||||||
private final AsyncDrawable drawable;
|
private final AsyncDrawable drawable;
|
||||||
private final int alignment;
|
private final int alignment;
|
||||||
private final boolean replacementTextIsLink;
|
private final boolean replacementTextIsLink;
|
||||||
|
|
||||||
public AsyncDrawableSpan(@NonNull SpannableTheme theme, @NonNull AsyncDrawable drawable) {
|
public AsyncDrawableSpan(@NonNull MarkwonTheme theme, @NonNull AsyncDrawable drawable) {
|
||||||
this(theme, drawable, ALIGN_BOTTOM);
|
this(theme, drawable, ALIGN_BOTTOM);
|
||||||
}
|
}
|
||||||
|
|
||||||
public AsyncDrawableSpan(
|
public AsyncDrawableSpan(
|
||||||
@NonNull SpannableTheme theme,
|
@NonNull MarkwonTheme theme,
|
||||||
@NonNull AsyncDrawable drawable,
|
@NonNull AsyncDrawable drawable,
|
||||||
@Alignment int alignment) {
|
@Alignment int alignment) {
|
||||||
this(theme, drawable, alignment, false);
|
this(theme, drawable, alignment, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public AsyncDrawableSpan(
|
public AsyncDrawableSpan(
|
||||||
@NonNull SpannableTheme theme,
|
@NonNull MarkwonTheme theme,
|
||||||
@NonNull AsyncDrawable drawable,
|
@NonNull AsyncDrawable drawable,
|
||||||
@Alignment int alignment,
|
@Alignment int alignment,
|
||||||
boolean replacementTextIsLink) {
|
boolean replacementTextIsLink) {
|
||||||
|
@ -9,11 +9,11 @@ import android.text.style.LeadingMarginSpan;
|
|||||||
|
|
||||||
public class BlockQuoteSpan implements LeadingMarginSpan {
|
public class BlockQuoteSpan implements LeadingMarginSpan {
|
||||||
|
|
||||||
private final SpannableTheme theme;
|
private final MarkwonTheme theme;
|
||||||
private final Rect rect = ObjectsPool.rect();
|
private final Rect rect = ObjectsPool.rect();
|
||||||
private final Paint paint = ObjectsPool.paint();
|
private final Paint paint = ObjectsPool.paint();
|
||||||
|
|
||||||
public BlockQuoteSpan(@NonNull SpannableTheme theme) {
|
public BlockQuoteSpan(@NonNull MarkwonTheme theme) {
|
||||||
this.theme = theme;
|
this.theme = theme;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,9 +9,11 @@ import android.support.annotation.NonNull;
|
|||||||
import android.text.Layout;
|
import android.text.Layout;
|
||||||
import android.text.style.LeadingMarginSpan;
|
import android.text.style.LeadingMarginSpan;
|
||||||
|
|
||||||
|
import ru.noties.markwon.utils.LeadingMarginUtils;
|
||||||
|
|
||||||
public class BulletListItemSpan implements LeadingMarginSpan {
|
public class BulletListItemSpan implements LeadingMarginSpan {
|
||||||
|
|
||||||
private SpannableTheme theme;
|
private MarkwonTheme theme;
|
||||||
|
|
||||||
private final Paint paint = ObjectsPool.paint();
|
private final Paint paint = ObjectsPool.paint();
|
||||||
private final RectF circle = ObjectsPool.rectF();
|
private final RectF circle = ObjectsPool.rectF();
|
||||||
@ -20,7 +22,7 @@ public class BulletListItemSpan implements LeadingMarginSpan {
|
|||||||
private final int level;
|
private final int level;
|
||||||
|
|
||||||
public BulletListItemSpan(
|
public BulletListItemSpan(
|
||||||
@NonNull SpannableTheme theme,
|
@NonNull MarkwonTheme theme,
|
||||||
@IntRange(from = 0) int level) {
|
@IntRange(from = 0) int level) {
|
||||||
this.theme = theme;
|
this.theme = theme;
|
||||||
this.level = level;
|
this.level = level;
|
||||||
|
@ -11,13 +11,13 @@ import android.text.style.MetricAffectingSpan;
|
|||||||
|
|
||||||
public class CodeSpan extends MetricAffectingSpan implements LeadingMarginSpan {
|
public class CodeSpan extends MetricAffectingSpan implements LeadingMarginSpan {
|
||||||
|
|
||||||
private final SpannableTheme theme;
|
private final MarkwonTheme theme;
|
||||||
private final Rect rect = ObjectsPool.rect();
|
private final Rect rect = ObjectsPool.rect();
|
||||||
private final Paint paint = ObjectsPool.paint();
|
private final Paint paint = ObjectsPool.paint();
|
||||||
|
|
||||||
private final boolean multiline;
|
private final boolean multiline;
|
||||||
|
|
||||||
public CodeSpan(@NonNull SpannableTheme theme, boolean multiline) {
|
public CodeSpan(@NonNull MarkwonTheme theme, boolean multiline) {
|
||||||
this.theme = theme;
|
this.theme = theme;
|
||||||
this.multiline = multiline;
|
this.multiline = multiline;
|
||||||
}
|
}
|
||||||
|
@ -10,14 +10,16 @@ import android.text.TextPaint;
|
|||||||
import android.text.style.LeadingMarginSpan;
|
import android.text.style.LeadingMarginSpan;
|
||||||
import android.text.style.MetricAffectingSpan;
|
import android.text.style.MetricAffectingSpan;
|
||||||
|
|
||||||
|
import ru.noties.markwon.utils.LeadingMarginUtils;
|
||||||
|
|
||||||
public class HeadingSpan extends MetricAffectingSpan implements LeadingMarginSpan {
|
public class HeadingSpan extends MetricAffectingSpan implements LeadingMarginSpan {
|
||||||
|
|
||||||
private final SpannableTheme theme;
|
private final MarkwonTheme theme;
|
||||||
private final Rect rect = ObjectsPool.rect();
|
private final Rect rect = ObjectsPool.rect();
|
||||||
private final Paint paint = ObjectsPool.paint();
|
private final Paint paint = ObjectsPool.paint();
|
||||||
private final int level;
|
private final int level;
|
||||||
|
|
||||||
public HeadingSpan(@NonNull SpannableTheme theme, @IntRange(from = 1, to = 6) int level) {
|
public HeadingSpan(@NonNull MarkwonTheme theme, @IntRange(from = 1, to = 6) int level) {
|
||||||
this.theme = theme;
|
this.theme = theme;
|
||||||
this.level = level;
|
this.level = level;
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,6 @@ package ru.noties.markwon.spans;
|
|||||||
|
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
import android.text.TextPaint;
|
import android.text.TextPaint;
|
||||||
import android.text.style.ClickableSpan;
|
|
||||||
import android.text.style.URLSpan;
|
import android.text.style.URLSpan;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
|
||||||
@ -12,11 +11,11 @@ public class LinkSpan extends URLSpan {
|
|||||||
void resolve(View view, @NonNull String link);
|
void resolve(View view, @NonNull String link);
|
||||||
}
|
}
|
||||||
|
|
||||||
private final SpannableTheme theme;
|
private final MarkwonTheme theme;
|
||||||
private final String link;
|
private final String link;
|
||||||
private final Resolver resolver;
|
private final Resolver resolver;
|
||||||
|
|
||||||
public LinkSpan(@NonNull SpannableTheme theme, @NonNull String link, @NonNull Resolver resolver) {
|
public LinkSpan(@NonNull MarkwonTheme theme, @NonNull String link, @NonNull Resolver resolver) {
|
||||||
super(link);
|
super(link);
|
||||||
this.theme = theme;
|
this.theme = theme;
|
||||||
this.link = link;
|
this.link = link;
|
||||||
|
@ -7,7 +7,6 @@ import android.graphics.Typeface;
|
|||||||
import android.graphics.drawable.Drawable;
|
import android.graphics.drawable.Drawable;
|
||||||
import android.support.annotation.AttrRes;
|
import android.support.annotation.AttrRes;
|
||||||
import android.support.annotation.ColorInt;
|
import android.support.annotation.ColorInt;
|
||||||
import android.support.annotation.Dimension;
|
|
||||||
import android.support.annotation.FloatRange;
|
import android.support.annotation.FloatRange;
|
||||||
import android.support.annotation.IntRange;
|
import android.support.annotation.IntRange;
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
@ -20,19 +19,21 @@ import android.util.TypedValue;
|
|||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
|
||||||
|
import ru.noties.markwon.tasklist.TaskListDrawable;
|
||||||
|
|
||||||
@SuppressWarnings("WeakerAccess")
|
@SuppressWarnings("WeakerAccess")
|
||||||
public class SpannableTheme {
|
public class MarkwonTheme {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Factory method to obtain an instance of {@link SpannableTheme} with all values as defaults
|
* Factory method to obtain an instance of {@link MarkwonTheme} with all values as defaults
|
||||||
*
|
*
|
||||||
* @param context Context in order to resolve defaults
|
* @param context Context in order to resolve defaults
|
||||||
* @return {@link SpannableTheme} instance
|
* @return {@link MarkwonTheme} instance
|
||||||
* @see #builderWithDefaults(Context)
|
* @see #builderWithDefaults(Context)
|
||||||
* @since 1.0.0
|
* @since 1.0.0
|
||||||
*/
|
*/
|
||||||
@NonNull
|
@NonNull
|
||||||
public static SpannableTheme create(@NonNull Context context) {
|
public static MarkwonTheme create(@NonNull Context context) {
|
||||||
return builderWithDefaults(context).build();
|
return builderWithDefaults(context).build();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -43,7 +44,7 @@ public class SpannableTheme {
|
|||||||
*
|
*
|
||||||
* @return {@link Builder instance}
|
* @return {@link Builder instance}
|
||||||
* @see #builderWithDefaults(Context)
|
* @see #builderWithDefaults(Context)
|
||||||
* @see #builder(SpannableTheme)
|
* @see #builder(MarkwonTheme)
|
||||||
* @since 1.0.0
|
* @since 1.0.0
|
||||||
*/
|
*/
|
||||||
@NonNull
|
@NonNull
|
||||||
@ -53,15 +54,15 @@ public class SpannableTheme {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Factory method to create a {@link Builder} instance and initialize it with values
|
* Factory method to create a {@link Builder} instance and initialize it with values
|
||||||
* from supplied {@link SpannableTheme}
|
* from supplied {@link MarkwonTheme}
|
||||||
*
|
*
|
||||||
* @param copyFrom {@link SpannableTheme} to copy values from
|
* @param copyFrom {@link MarkwonTheme} to copy values from
|
||||||
* @return {@link Builder} instance
|
* @return {@link Builder} instance
|
||||||
* @see #builderWithDefaults(Context)
|
* @see #builderWithDefaults(Context)
|
||||||
* @since 1.0.0
|
* @since 1.0.0
|
||||||
*/
|
*/
|
||||||
@NonNull
|
@NonNull
|
||||||
public static Builder builder(@NonNull SpannableTheme copyFrom) {
|
public static Builder builder(@NonNull MarkwonTheme copyFrom) {
|
||||||
return new Builder(copyFrom);
|
return new Builder(copyFrom);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -217,9 +218,10 @@ public class SpannableTheme {
|
|||||||
|
|
||||||
// drawable that will be used to render checkbox (should be stateful)
|
// drawable that will be used to render checkbox (should be stateful)
|
||||||
// TaskListDrawable can be used
|
// TaskListDrawable can be used
|
||||||
|
@Deprecated
|
||||||
protected final Drawable taskListDrawable;
|
protected final Drawable taskListDrawable;
|
||||||
|
|
||||||
protected SpannableTheme(@NonNull Builder builder) {
|
protected MarkwonTheme(@NonNull Builder builder) {
|
||||||
this.linkColor = builder.linkColor;
|
this.linkColor = builder.linkColor;
|
||||||
this.blockMargin = builder.blockMargin;
|
this.blockMargin = builder.blockMargin;
|
||||||
this.blockQuoteWidth = builder.blockQuoteWidth;
|
this.blockQuoteWidth = builder.blockQuoteWidth;
|
||||||
@ -526,6 +528,7 @@ public class SpannableTheme {
|
|||||||
* @since 1.0.1
|
* @since 1.0.1
|
||||||
*/
|
*/
|
||||||
@Nullable
|
@Nullable
|
||||||
|
@Deprecated
|
||||||
public Drawable getTaskListDrawable() {
|
public Drawable getTaskListDrawable() {
|
||||||
return taskListDrawable;
|
return taskListDrawable;
|
||||||
}
|
}
|
||||||
@ -565,7 +568,7 @@ public class SpannableTheme {
|
|||||||
Builder() {
|
Builder() {
|
||||||
}
|
}
|
||||||
|
|
||||||
Builder(@NonNull SpannableTheme theme) {
|
Builder(@NonNull MarkwonTheme theme) {
|
||||||
this.linkColor = theme.linkColor;
|
this.linkColor = theme.linkColor;
|
||||||
this.blockMargin = theme.blockMargin;
|
this.blockMargin = theme.blockMargin;
|
||||||
this.blockQuoteWidth = theme.blockQuoteWidth;
|
this.blockQuoteWidth = theme.blockQuoteWidth;
|
||||||
@ -792,14 +795,15 @@ public class SpannableTheme {
|
|||||||
* @since 1.0.1
|
* @since 1.0.1
|
||||||
*/
|
*/
|
||||||
@NonNull
|
@NonNull
|
||||||
|
@Deprecated
|
||||||
public Builder taskListDrawable(@NonNull Drawable taskListDrawable) {
|
public Builder taskListDrawable(@NonNull Drawable taskListDrawable) {
|
||||||
this.taskListDrawable = taskListDrawable;
|
this.taskListDrawable = taskListDrawable;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
public SpannableTheme build() {
|
public MarkwonTheme build() {
|
||||||
return new SpannableTheme(this);
|
return new MarkwonTheme(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -9,6 +9,8 @@ import android.text.TextPaint;
|
|||||||
import android.text.style.LeadingMarginSpan;
|
import android.text.style.LeadingMarginSpan;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import ru.noties.markwon.utils.LeadingMarginUtils;
|
||||||
|
|
||||||
public class OrderedListItemSpan implements LeadingMarginSpan {
|
public class OrderedListItemSpan implements LeadingMarginSpan {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -42,7 +44,7 @@ public class OrderedListItemSpan implements LeadingMarginSpan {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private final SpannableTheme theme;
|
private final MarkwonTheme theme;
|
||||||
private final String number;
|
private final String number;
|
||||||
private final Paint paint = ObjectsPool.paint();
|
private final Paint paint = ObjectsPool.paint();
|
||||||
|
|
||||||
@ -52,7 +54,7 @@ public class OrderedListItemSpan implements LeadingMarginSpan {
|
|||||||
private int margin;
|
private int margin;
|
||||||
|
|
||||||
public OrderedListItemSpan(
|
public OrderedListItemSpan(
|
||||||
@NonNull SpannableTheme theme,
|
@NonNull MarkwonTheme theme,
|
||||||
@NonNull String number
|
@NonNull String number
|
||||||
) {
|
) {
|
||||||
this.theme = theme;
|
this.theme = theme;
|
||||||
|
@ -6,9 +6,9 @@ import android.text.style.MetricAffectingSpan;
|
|||||||
|
|
||||||
public class SubScriptSpan extends MetricAffectingSpan {
|
public class SubScriptSpan extends MetricAffectingSpan {
|
||||||
|
|
||||||
private final SpannableTheme theme;
|
private final MarkwonTheme theme;
|
||||||
|
|
||||||
public SubScriptSpan(@NonNull SpannableTheme theme) {
|
public SubScriptSpan(@NonNull MarkwonTheme theme) {
|
||||||
this.theme = theme;
|
this.theme = theme;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,9 +6,9 @@ import android.text.style.MetricAffectingSpan;
|
|||||||
|
|
||||||
public class SuperScriptSpan extends MetricAffectingSpan {
|
public class SuperScriptSpan extends MetricAffectingSpan {
|
||||||
|
|
||||||
private final SpannableTheme theme;
|
private final MarkwonTheme theme;
|
||||||
|
|
||||||
public SuperScriptSpan(@NonNull SpannableTheme theme) {
|
public SuperScriptSpan(@NonNull MarkwonTheme theme) {
|
||||||
this.theme = theme;
|
this.theme = theme;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -61,7 +61,7 @@ public class TableRowSpan extends ReplacementSpan {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private final SpannableTheme theme;
|
private final MarkwonTheme theme;
|
||||||
private final List<Cell> cells;
|
private final List<Cell> cells;
|
||||||
private final List<StaticLayout> layouts;
|
private final List<StaticLayout> layouts;
|
||||||
private final TextPaint textPaint;
|
private final TextPaint textPaint;
|
||||||
@ -76,7 +76,7 @@ public class TableRowSpan extends ReplacementSpan {
|
|||||||
private Invalidator invalidator;
|
private Invalidator invalidator;
|
||||||
|
|
||||||
public TableRowSpan(
|
public TableRowSpan(
|
||||||
@NonNull SpannableTheme theme,
|
@NonNull MarkwonTheme theme,
|
||||||
@NonNull List<Cell> cells,
|
@NonNull List<Cell> cells,
|
||||||
boolean header,
|
boolean header,
|
||||||
boolean odd) {
|
boolean odd) {
|
||||||
|
@ -9,11 +9,11 @@ import android.text.style.LeadingMarginSpan;
|
|||||||
|
|
||||||
public class ThematicBreakSpan implements LeadingMarginSpan {
|
public class ThematicBreakSpan implements LeadingMarginSpan {
|
||||||
|
|
||||||
private final SpannableTheme theme;
|
private final MarkwonTheme theme;
|
||||||
private final Rect rect = ObjectsPool.rect();
|
private final Rect rect = ObjectsPool.rect();
|
||||||
private final Paint paint = ObjectsPool.paint();
|
private final Paint paint = ObjectsPool.paint();
|
||||||
|
|
||||||
public ThematicBreakSpan(@NonNull SpannableTheme theme) {
|
public ThematicBreakSpan(@NonNull MarkwonTheme theme) {
|
||||||
this.theme = theme;
|
this.theme = theme;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
package ru.noties.markwon.spans;
|
package ru.noties.markwon.tasklist;
|
||||||
|
|
||||||
import android.graphics.Canvas;
|
import android.graphics.Canvas;
|
||||||
import android.graphics.ColorFilter;
|
import android.graphics.ColorFilter;
|
@ -7,6 +7,7 @@ import org.commonmark.parser.Parser;
|
|||||||
/**
|
/**
|
||||||
* @since 1.0.1
|
* @since 1.0.1
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public class TaskListExtension implements Parser.ParserExtension {
|
public class TaskListExtension implements Parser.ParserExtension {
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
|
@ -0,0 +1,93 @@
|
|||||||
|
package ru.noties.markwon.tasklist;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.graphics.drawable.Drawable;
|
||||||
|
import android.support.annotation.ColorInt;
|
||||||
|
import android.support.annotation.NonNull;
|
||||||
|
|
||||||
|
import org.commonmark.parser.Parser;
|
||||||
|
|
||||||
|
import ru.noties.markwon.AbstractMarkwonPlugin;
|
||||||
|
import ru.noties.markwon.MarkwonVisitor;
|
||||||
|
|
||||||
|
public class TaskListPlugin extends AbstractMarkwonPlugin {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see TaskListDrawable
|
||||||
|
*/
|
||||||
|
@NonNull
|
||||||
|
public static TaskListPlugin create(@NonNull Drawable drawable) {
|
||||||
|
return new TaskListPlugin(drawable);
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
public static TaskListPlugin create(@NonNull Context context) {
|
||||||
|
// resolve link color and background color
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
public static TaskListPlugin create(
|
||||||
|
@ColorInt int checkedFillColor,
|
||||||
|
@ColorInt int normalOutlineColor,
|
||||||
|
@ColorInt int checkMarkColor) {
|
||||||
|
return new TaskListPlugin(new TaskListDrawable(
|
||||||
|
checkedFillColor,
|
||||||
|
normalOutlineColor,
|
||||||
|
checkMarkColor));
|
||||||
|
}
|
||||||
|
|
||||||
|
private final Drawable drawable;
|
||||||
|
|
||||||
|
private TaskListPlugin(@NonNull Drawable drawable) {
|
||||||
|
this.drawable = drawable;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void configureParser(@NonNull Parser.Builder builder) {
|
||||||
|
builder.customBlockParserFactory(new TaskListBlockParser.Factory());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void configureVisitor(@NonNull MarkwonVisitor.Builder builder) {
|
||||||
|
builder
|
||||||
|
.on(TaskListBlock.class, new MarkwonVisitor.NodeVisitor<TaskListBlock>() {
|
||||||
|
@Override
|
||||||
|
public void visit(@NonNull MarkwonVisitor visitor, @NonNull TaskListBlock taskListBlock) {
|
||||||
|
|
||||||
|
visitor.ensureNewLine();
|
||||||
|
|
||||||
|
visitor.incrementBlockQuoteIndent();
|
||||||
|
visitor.visitChildren(taskListBlock);
|
||||||
|
visitor.decrementBlockQuoteIndent();
|
||||||
|
|
||||||
|
if (visitor.hasNext(taskListBlock)) {
|
||||||
|
visitor.ensureNewLine();
|
||||||
|
visitor.forceNewLine();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.on(TaskListItem.class, new MarkwonVisitor.NodeVisitor<TaskListItem>() {
|
||||||
|
@Override
|
||||||
|
public void visit(@NonNull MarkwonVisitor visitor, @NonNull TaskListItem taskListItem) {
|
||||||
|
|
||||||
|
final int length = visitor.length();
|
||||||
|
|
||||||
|
final int indent = visitor.blockQuoteIndent();
|
||||||
|
visitor.blockQuoteIntent(indent + taskListItem.indent());
|
||||||
|
visitor.visitChildren(taskListItem);
|
||||||
|
visitor.setSpans(length, new TaskListSpan(
|
||||||
|
visitor.theme(),
|
||||||
|
drawable,
|
||||||
|
visitor.blockQuoteIndent(),
|
||||||
|
taskListItem.done()));
|
||||||
|
|
||||||
|
if (visitor.hasNext(taskListItem)) {
|
||||||
|
visitor.ensureNewLine();
|
||||||
|
}
|
||||||
|
|
||||||
|
visitor.blockQuoteIntent(indent);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
package ru.noties.markwon.spans;
|
package ru.noties.markwon.tasklist;
|
||||||
|
|
||||||
import android.graphics.Canvas;
|
import android.graphics.Canvas;
|
||||||
import android.graphics.Paint;
|
import android.graphics.Paint;
|
||||||
@ -7,6 +7,9 @@ import android.support.annotation.NonNull;
|
|||||||
import android.text.Layout;
|
import android.text.Layout;
|
||||||
import android.text.style.LeadingMarginSpan;
|
import android.text.style.LeadingMarginSpan;
|
||||||
|
|
||||||
|
import ru.noties.markwon.spans.MarkwonTheme;
|
||||||
|
import ru.noties.markwon.utils.LeadingMarginUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @since 1.0.1
|
* @since 1.0.1
|
||||||
*/
|
*/
|
||||||
@ -16,14 +19,24 @@ public class TaskListSpan implements LeadingMarginSpan {
|
|||||||
|
|
||||||
private static final int[] STATE_NONE = new int[0];
|
private static final int[] STATE_NONE = new int[0];
|
||||||
|
|
||||||
private final SpannableTheme theme;
|
private final MarkwonTheme theme;
|
||||||
|
private final Drawable drawable;
|
||||||
private final int blockIndent;
|
private final int blockIndent;
|
||||||
|
|
||||||
// @since 2.0.1 field is NOT final (to allow mutation)
|
// @since 2.0.1 field is NOT final (to allow mutation)
|
||||||
private boolean isDone;
|
private boolean isDone;
|
||||||
|
|
||||||
public TaskListSpan(@NonNull SpannableTheme theme, int blockIndent, boolean isDone) {
|
@Deprecated
|
||||||
|
public TaskListSpan(@NonNull MarkwonTheme theme, int blockIndent, boolean isDone) {
|
||||||
this.theme = theme;
|
this.theme = theme;
|
||||||
|
this.drawable = null;
|
||||||
|
this.blockIndent = blockIndent;
|
||||||
|
this.isDone = isDone;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TaskListSpan(@NonNull MarkwonTheme theme, @NonNull Drawable drawable, int blockIndent, boolean isDone) {
|
||||||
|
this.theme = theme;
|
||||||
|
this.drawable = drawable;
|
||||||
this.blockIndent = blockIndent;
|
this.blockIndent = blockIndent;
|
||||||
this.isDone = isDone;
|
this.isDone = isDone;
|
||||||
}
|
}
|
||||||
@ -58,10 +71,10 @@ public class TaskListSpan implements LeadingMarginSpan {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
final Drawable drawable = theme.getTaskListDrawable();
|
// final Drawable drawable = theme.getTaskListDrawable();
|
||||||
if (drawable == null) {
|
// if (drawable == null) {
|
||||||
return;
|
// return;
|
||||||
}
|
// }
|
||||||
|
|
||||||
final int save = c.save();
|
final int save = c.save();
|
||||||
try {
|
try {
|
@ -1,14 +1,14 @@
|
|||||||
package ru.noties.markwon.spans;
|
package ru.noties.markwon.utils;
|
||||||
|
|
||||||
import android.text.Spanned;
|
import android.text.Spanned;
|
||||||
|
|
||||||
abstract class LeadingMarginUtils {
|
public abstract class LeadingMarginUtils {
|
||||||
|
|
||||||
static boolean selfStart(int start, CharSequence text, Object span) {
|
public static boolean selfStart(int start, CharSequence text, Object span) {
|
||||||
return text instanceof Spanned && ((Spanned) text).getSpanStart(span) == start;
|
return text instanceof Spanned && ((Spanned) text).getSpanStart(span) == start;
|
||||||
}
|
}
|
||||||
|
|
||||||
static boolean selfEnd(int end, CharSequence text, Object span) {
|
public static boolean selfEnd(int end, CharSequence text, Object span) {
|
||||||
return text instanceof Spanned && ((Spanned) text).getSpanEnd(span) == end;
|
return text instanceof Spanned && ((Spanned) text).getSpanEnd(span) == end;
|
||||||
}
|
}
|
||||||
|
|
@ -2,7 +2,7 @@ package ru.noties.markwon.renderer;
|
|||||||
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import ru.noties.markwon.SpannableConfiguration;
|
import ru.noties.markwon.MarkwonConfiguration;
|
||||||
import ru.noties.markwon.SpannableFactory;
|
import ru.noties.markwon.SpannableFactory;
|
||||||
import ru.noties.markwon.SyntaxHighlight;
|
import ru.noties.markwon.SyntaxHighlight;
|
||||||
import ru.noties.markwon.UrlProcessor;
|
import ru.noties.markwon.UrlProcessor;
|
||||||
@ -10,17 +10,17 @@ import ru.noties.markwon.html.api.MarkwonHtmlParser;
|
|||||||
import ru.noties.markwon.renderer.html2.MarkwonHtmlRenderer;
|
import ru.noties.markwon.renderer.html2.MarkwonHtmlRenderer;
|
||||||
import ru.noties.markwon.spans.AsyncDrawable;
|
import ru.noties.markwon.spans.AsyncDrawable;
|
||||||
import ru.noties.markwon.spans.LinkSpan;
|
import ru.noties.markwon.spans.LinkSpan;
|
||||||
import ru.noties.markwon.spans.SpannableTheme;
|
import ru.noties.markwon.spans.MarkwonTheme;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.mockito.Mockito.mock;
|
import static org.mockito.Mockito.mock;
|
||||||
public class SpannableConfigurationTest {
|
public class MarkwonConfigurationTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testNewBuilder() {
|
public void testNewBuilder() {
|
||||||
final SpannableConfiguration configuration = SpannableConfiguration
|
final MarkwonConfiguration configuration = MarkwonConfiguration
|
||||||
.builder(null)
|
.builder(null)
|
||||||
.theme(mock(SpannableTheme.class))
|
.theme(mock(MarkwonTheme.class))
|
||||||
.asyncDrawableLoader(mock(AsyncDrawable.Loader.class))
|
.asyncDrawableLoader(mock(AsyncDrawable.Loader.class))
|
||||||
.syntaxHighlight(mock(SyntaxHighlight.class))
|
.syntaxHighlight(mock(SyntaxHighlight.class))
|
||||||
.linkResolver(mock(LinkSpan.Resolver.class))
|
.linkResolver(mock(LinkSpan.Resolver.class))
|
||||||
@ -33,7 +33,7 @@ public class SpannableConfigurationTest {
|
|||||||
.htmlAllowNonClosedTags(true)
|
.htmlAllowNonClosedTags(true)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
final SpannableConfiguration newConfiguration = configuration
|
final MarkwonConfiguration newConfiguration = configuration
|
||||||
.newBuilder(null)
|
.newBuilder(null)
|
||||||
.build();
|
.build();
|
||||||
|
|
@ -13,11 +13,11 @@ import org.junit.runner.RunWith;
|
|||||||
import org.robolectric.RobolectricTestRunner;
|
import org.robolectric.RobolectricTestRunner;
|
||||||
import org.robolectric.annotation.Config;
|
import org.robolectric.annotation.Config;
|
||||||
|
|
||||||
|
import ru.noties.markwon.MarkwonConfiguration;
|
||||||
import ru.noties.markwon.SpannableBuilder;
|
import ru.noties.markwon.SpannableBuilder;
|
||||||
import ru.noties.markwon.SpannableConfiguration;
|
|
||||||
import ru.noties.markwon.SpannableFactory;
|
import ru.noties.markwon.SpannableFactory;
|
||||||
import ru.noties.markwon.SyntaxHighlight;
|
import ru.noties.markwon.SyntaxHighlight;
|
||||||
import ru.noties.markwon.spans.SpannableTheme;
|
import ru.noties.markwon.spans.MarkwonTheme;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
@ -63,12 +63,12 @@ public class SyntaxHighlightTest {
|
|||||||
};
|
};
|
||||||
|
|
||||||
final SpannableFactory factory = mock(SpannableFactory.class);
|
final SpannableFactory factory = mock(SpannableFactory.class);
|
||||||
when(factory.code(any(SpannableTheme.class), anyBoolean())).thenReturn(codeSpan);
|
when(factory.code(any(MarkwonTheme.class), anyBoolean())).thenReturn(codeSpan);
|
||||||
|
|
||||||
final SpannableConfiguration configuration = SpannableConfiguration.builder(mock(Context.class))
|
final MarkwonConfiguration configuration = MarkwonConfiguration.builder(mock(Context.class))
|
||||||
.syntaxHighlight(highlight)
|
.syntaxHighlight(highlight)
|
||||||
.factory(factory)
|
.factory(factory)
|
||||||
.theme(mock(SpannableTheme.class))
|
.theme(mock(MarkwonTheme.class))
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
final SpannableBuilder builder = new SpannableBuilder();
|
final SpannableBuilder builder = new SpannableBuilder();
|
||||||
|
@ -14,12 +14,12 @@ import java.util.Collection;
|
|||||||
|
|
||||||
import ru.noties.markwon.LinkResolverDef;
|
import ru.noties.markwon.LinkResolverDef;
|
||||||
import ru.noties.markwon.Markwon;
|
import ru.noties.markwon.Markwon;
|
||||||
|
import ru.noties.markwon.MarkwonConfiguration;
|
||||||
import ru.noties.markwon.SpannableBuilder;
|
import ru.noties.markwon.SpannableBuilder;
|
||||||
import ru.noties.markwon.SpannableConfiguration;
|
|
||||||
import ru.noties.markwon.SpannableFactory;
|
import ru.noties.markwon.SpannableFactory;
|
||||||
import ru.noties.markwon.html.api.MarkwonHtmlParser;
|
import ru.noties.markwon.html.api.MarkwonHtmlParser;
|
||||||
import ru.noties.markwon.renderer.SpannableMarkdownVisitor;
|
import ru.noties.markwon.renderer.SpannableMarkdownVisitor;
|
||||||
import ru.noties.markwon.spans.SpannableTheme;
|
import ru.noties.markwon.spans.MarkwonTheme;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.mockito.Mockito.mock;
|
import static org.mockito.Mockito.mock;
|
||||||
@ -44,7 +44,7 @@ public class SpannableMarkdownVisitorTest {
|
|||||||
|
|
||||||
final TestData data = TestDataReader.readTest(file);
|
final TestData data = TestDataReader.readTest(file);
|
||||||
|
|
||||||
final SpannableConfiguration configuration = configuration(data.config());
|
final MarkwonConfiguration configuration = configuration(data.config());
|
||||||
final SpannableBuilder builder = new SpannableBuilder();
|
final SpannableBuilder builder = new SpannableBuilder();
|
||||||
final SpannableMarkdownVisitor visitor = new SpannableMarkdownVisitor(configuration, builder);
|
final SpannableMarkdownVisitor visitor = new SpannableMarkdownVisitor(configuration, builder);
|
||||||
final Node node = Markwon.createParser().parse(data.input());
|
final Node node = Markwon.createParser().parse(data.input());
|
||||||
@ -73,7 +73,7 @@ public class SpannableMarkdownVisitorTest {
|
|||||||
|
|
||||||
@SuppressWarnings("ConstantConditions")
|
@SuppressWarnings("ConstantConditions")
|
||||||
@NonNull
|
@NonNull
|
||||||
private SpannableConfiguration configuration(@NonNull TestConfig config) {
|
private MarkwonConfiguration configuration(@NonNull TestConfig config) {
|
||||||
|
|
||||||
final SpannableFactory factory = new TestFactory(config.hasOption(TestConfig.USE_PARAGRAPHS));
|
final SpannableFactory factory = new TestFactory(config.hasOption(TestConfig.USE_PARAGRAPHS));
|
||||||
final MarkwonHtmlParser htmlParser = config.hasOption(TestConfig.USE_HTML)
|
final MarkwonHtmlParser htmlParser = config.hasOption(TestConfig.USE_HTML)
|
||||||
@ -83,8 +83,8 @@ public class SpannableMarkdownVisitorTest {
|
|||||||
final boolean softBreakAddsNewLine = config.hasOption(TestConfig.SOFT_BREAK_ADDS_NEW_LINE);
|
final boolean softBreakAddsNewLine = config.hasOption(TestConfig.SOFT_BREAK_ADDS_NEW_LINE);
|
||||||
final boolean htmlAllowNonClosedTags = config.hasOption(TestConfig.HTML_ALLOW_NON_CLOSED_TAGS);
|
final boolean htmlAllowNonClosedTags = config.hasOption(TestConfig.HTML_ALLOW_NON_CLOSED_TAGS);
|
||||||
|
|
||||||
return SpannableConfiguration.builder(null)
|
return MarkwonConfiguration.builder(null)
|
||||||
.theme(mock(SpannableTheme.class))
|
.theme(mock(MarkwonTheme.class))
|
||||||
.linkResolver(mock(LinkResolverDef.class))
|
.linkResolver(mock(LinkResolverDef.class))
|
||||||
.htmlParser(htmlParser)
|
.htmlParser(htmlParser)
|
||||||
.factory(factory)
|
.factory(factory)
|
||||||
|
@ -13,7 +13,7 @@ import ru.noties.markwon.renderer.ImageSize;
|
|||||||
import ru.noties.markwon.renderer.ImageSizeResolver;
|
import ru.noties.markwon.renderer.ImageSizeResolver;
|
||||||
import ru.noties.markwon.spans.AsyncDrawable;
|
import ru.noties.markwon.spans.AsyncDrawable;
|
||||||
import ru.noties.markwon.spans.LinkSpan;
|
import ru.noties.markwon.spans.LinkSpan;
|
||||||
import ru.noties.markwon.spans.SpannableTheme;
|
import ru.noties.markwon.spans.MarkwonTheme;
|
||||||
import ru.noties.markwon.spans.TableRowSpan;
|
import ru.noties.markwon.spans.TableRowSpan;
|
||||||
|
|
||||||
import static ru.noties.markwon.renderer.visitor.TestSpan.BLOCK_QUOTE;
|
import static ru.noties.markwon.renderer.visitor.TestSpan.BLOCK_QUOTE;
|
||||||
@ -57,13 +57,13 @@ class TestFactory implements SpannableFactory {
|
|||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
public Object blockQuote(@NonNull SpannableTheme theme) {
|
public Object blockQuote(@NonNull MarkwonTheme theme) {
|
||||||
return new TestSpan(BLOCK_QUOTE);
|
return new TestSpan(BLOCK_QUOTE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
public Object code(@NonNull SpannableTheme theme, boolean multiline) {
|
public Object code(@NonNull MarkwonTheme theme, boolean multiline) {
|
||||||
final String name = multiline
|
final String name = multiline
|
||||||
? CODE_BLOCK
|
? CODE_BLOCK
|
||||||
: CODE;
|
: CODE;
|
||||||
@ -72,25 +72,25 @@ class TestFactory implements SpannableFactory {
|
|||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
public Object orderedListItem(@NonNull SpannableTheme theme, int startNumber) {
|
public Object orderedListItem(@NonNull MarkwonTheme theme, int startNumber) {
|
||||||
return new TestSpan(ORDERED_LIST, map("start", startNumber));
|
return new TestSpan(ORDERED_LIST, map("start", startNumber));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
public Object bulletListItem(@NonNull SpannableTheme theme, int level) {
|
public Object bulletListItem(@NonNull MarkwonTheme theme, int level) {
|
||||||
return new TestSpan(BULLET_LIST, map("level", level));
|
return new TestSpan(BULLET_LIST, map("level", level));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
public Object thematicBreak(@NonNull SpannableTheme theme) {
|
public Object thematicBreak(@NonNull MarkwonTheme theme) {
|
||||||
return new TestSpan(THEMATIC_BREAK);
|
return new TestSpan(THEMATIC_BREAK);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
public Object heading(@NonNull SpannableTheme theme, int level) {
|
public Object heading(@NonNull MarkwonTheme theme, int level) {
|
||||||
return new TestSpan(HEADING + level);
|
return new TestSpan(HEADING + level);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -102,7 +102,7 @@ class TestFactory implements SpannableFactory {
|
|||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
public Object taskListItem(@NonNull SpannableTheme theme, int blockIndent, boolean isDone) {
|
public Object taskListItem(@NonNull MarkwonTheme theme, int blockIndent, boolean isDone) {
|
||||||
return new TestSpan(TASK_LIST, map(
|
return new TestSpan(TASK_LIST, map(
|
||||||
Pair.of("blockIdent", blockIndent),
|
Pair.of("blockIdent", blockIndent),
|
||||||
Pair.of("done", isDone)
|
Pair.of("done", isDone)
|
||||||
@ -111,7 +111,7 @@ class TestFactory implements SpannableFactory {
|
|||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
public Object tableRow(@NonNull SpannableTheme theme, @NonNull List<TableRowSpan.Cell> cells, boolean isHeader, boolean isOdd) {
|
public Object tableRow(@NonNull MarkwonTheme theme, @NonNull List<TableRowSpan.Cell> cells, boolean isHeader, boolean isOdd) {
|
||||||
return new TestSpan(TABLE_ROW, map(
|
return new TestSpan(TABLE_ROW, map(
|
||||||
Pair.of("cells", cells),
|
Pair.of("cells", cells),
|
||||||
Pair.of("header", isHeader),
|
Pair.of("header", isHeader),
|
||||||
@ -129,7 +129,7 @@ class TestFactory implements SpannableFactory {
|
|||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
public Object image(@NonNull SpannableTheme theme, @NonNull String destination, @NonNull AsyncDrawable.Loader loader, @NonNull ImageSizeResolver imageSizeResolver, @Nullable ImageSize imageSize, boolean replacementTextIsLink) {
|
public Object image(@NonNull MarkwonTheme theme, @NonNull String destination, @NonNull AsyncDrawable.Loader loader, @NonNull ImageSizeResolver imageSizeResolver, @Nullable ImageSize imageSize, boolean replacementTextIsLink) {
|
||||||
return new TestSpan(IMAGE, map(
|
return new TestSpan(IMAGE, map(
|
||||||
Pair.of("src", destination),
|
Pair.of("src", destination),
|
||||||
Pair.of("imageSize", imageSize),
|
Pair.of("imageSize", imageSize),
|
||||||
@ -139,19 +139,19 @@ class TestFactory implements SpannableFactory {
|
|||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
public Object link(@NonNull SpannableTheme theme, @NonNull String destination, @NonNull LinkSpan.Resolver resolver) {
|
public Object link(@NonNull MarkwonTheme theme, @NonNull String destination, @NonNull LinkSpan.Resolver resolver) {
|
||||||
return new TestSpan(LINK, map("href", destination));
|
return new TestSpan(LINK, map("href", destination));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
public Object superScript(@NonNull SpannableTheme theme) {
|
public Object superScript(@NonNull MarkwonTheme theme) {
|
||||||
return new TestSpan(SUPER_SCRIPT);
|
return new TestSpan(SUPER_SCRIPT);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
public Object subScript(@NonNull SpannableTheme theme) {
|
public Object subScript(@NonNull MarkwonTheme theme) {
|
||||||
return new TestSpan(SUB_SCRIPT);
|
return new TestSpan(SUB_SCRIPT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,12 +2,11 @@ package ru.noties.markwon.sample.extension;
|
|||||||
|
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.widget.TextView;
|
|
||||||
|
|
||||||
import org.commonmark.node.CustomNode;
|
import org.commonmark.node.CustomNode;
|
||||||
|
|
||||||
import ru.noties.markwon.SpannableBuilder;
|
import ru.noties.markwon.SpannableBuilder;
|
||||||
import ru.noties.markwon.SpannableConfiguration;
|
import ru.noties.markwon.MarkwonConfiguration;
|
||||||
import ru.noties.markwon.renderer.SpannableMarkdownVisitor;
|
import ru.noties.markwon.renderer.SpannableMarkdownVisitor;
|
||||||
|
|
||||||
@SuppressWarnings("WeakerAccess")
|
@SuppressWarnings("WeakerAccess")
|
||||||
@ -18,7 +17,7 @@ public class IconVisitor extends SpannableMarkdownVisitor {
|
|||||||
private final IconSpanProvider iconSpanProvider;
|
private final IconSpanProvider iconSpanProvider;
|
||||||
|
|
||||||
public IconVisitor(
|
public IconVisitor(
|
||||||
@NonNull SpannableConfiguration configuration,
|
@NonNull MarkwonConfiguration configuration,
|
||||||
@NonNull SpannableBuilder builder,
|
@NonNull SpannableBuilder builder,
|
||||||
@NonNull IconSpanProvider iconSpanProvider
|
@NonNull IconSpanProvider iconSpanProvider
|
||||||
) {
|
) {
|
||||||
|
@ -12,9 +12,9 @@ import org.commonmark.parser.Parser;
|
|||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
import ru.noties.markwon.MarkwonConfiguration;
|
||||||
import ru.noties.markwon.SpannableBuilder;
|
import ru.noties.markwon.SpannableBuilder;
|
||||||
import ru.noties.markwon.SpannableConfiguration;
|
import ru.noties.markwon.spans.MarkwonTheme;
|
||||||
import ru.noties.markwon.spans.SpannableTheme;
|
|
||||||
import ru.noties.markwon.tasklist.TaskListExtension;
|
import ru.noties.markwon.tasklist.TaskListExtension;
|
||||||
|
|
||||||
public class MainActivity extends Activity {
|
public class MainActivity extends Activity {
|
||||||
@ -53,8 +53,8 @@ public class MainActivity extends Activity {
|
|||||||
final IconSpanProvider spanProvider = IconSpanProvider.create(this, 0);
|
final IconSpanProvider spanProvider = IconSpanProvider.create(this, 0);
|
||||||
|
|
||||||
final float[] textSizeMultipliers = new float[]{3f, 2f, 1.5f, 1f, .5f, .25f};
|
final float[] textSizeMultipliers = new float[]{3f, 2f, 1.5f, 1f, .5f, .25f};
|
||||||
SpannableConfiguration configuration = SpannableConfiguration.builder(this)
|
MarkwonConfiguration configuration = MarkwonConfiguration.builder(this)
|
||||||
.theme(SpannableTheme.builder()
|
.theme(MarkwonTheme.builder()
|
||||||
.headingTypeface(Typeface.MONOSPACE)
|
.headingTypeface(Typeface.MONOSPACE)
|
||||||
.headingTextSizeMultipliers(textSizeMultipliers)
|
.headingTextSizeMultipliers(textSizeMultipliers)
|
||||||
.build())
|
.build())
|
||||||
|
@ -10,8 +10,8 @@ import org.commonmark.parser.Parser;
|
|||||||
|
|
||||||
import ru.noties.jlatexmath.JLatexMathAndroid;
|
import ru.noties.jlatexmath.JLatexMathAndroid;
|
||||||
import ru.noties.markwon.Markwon;
|
import ru.noties.markwon.Markwon;
|
||||||
|
import ru.noties.markwon.MarkwonConfiguration;
|
||||||
import ru.noties.markwon.SpannableBuilder;
|
import ru.noties.markwon.SpannableBuilder;
|
||||||
import ru.noties.markwon.SpannableConfiguration;
|
|
||||||
import ru.noties.markwon.il.AsyncDrawableLoader;
|
import ru.noties.markwon.il.AsyncDrawableLoader;
|
||||||
import ru.noties.markwon.renderer.ImageSize;
|
import ru.noties.markwon.renderer.ImageSize;
|
||||||
import ru.noties.markwon.renderer.SpannableMarkdownVisitor;
|
import ru.noties.markwon.renderer.SpannableMarkdownVisitor;
|
||||||
@ -55,7 +55,7 @@ public class MainActivity extends Activity {
|
|||||||
.mediaDecoders(jLatexMathMedia.mediaDecoder())
|
.mediaDecoders(jLatexMathMedia.mediaDecoder())
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
final SpannableConfiguration configuration = SpannableConfiguration.builder(this)
|
final MarkwonConfiguration configuration = MarkwonConfiguration.builder(this)
|
||||||
.asyncDrawableLoader(asyncDrawableLoader)
|
.asyncDrawableLoader(asyncDrawableLoader)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
@ -68,7 +68,7 @@ public class MainActivity extends Activity {
|
|||||||
|
|
||||||
final Node node = parser.parse(markdown);
|
final Node node = parser.parse(markdown);
|
||||||
final SpannableBuilder builder = new SpannableBuilder();
|
final SpannableBuilder builder = new SpannableBuilder();
|
||||||
final SpannableMarkdownVisitor visitor = new SpannableMarkdownVisitor(SpannableConfiguration.create(this), builder) {
|
final SpannableMarkdownVisitor visitor = new SpannableMarkdownVisitor(MarkwonConfiguration.create(this), builder) {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(CustomBlock customBlock) {
|
public void visit(CustomBlock customBlock) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user