Split code and codeBlock spans and factories
This commit is contained in:
		
							parent
							
								
									e1d5530962
								
							
						
					
					
						commit
						0a965e4cbc
					
				| @ -116,7 +116,7 @@ The color of background of code block text | ||||
| 
 | ||||
| Leading margin for the block code content | ||||
| 
 | ||||
| <ThemeProperty name="codeMultilineMargin" type="@Px int" defaults="Width of the space character" /> | ||||
| <ThemeProperty name="codeMultilineMargin" type="@Px int" defaults="8dip" /> | ||||
| 
 | ||||
| ### Code typeface | ||||
| 
 | ||||
|  | ||||
| @ -120,7 +120,7 @@ The color of background of code block text | ||||
| 
 | ||||
| Leading margin for the block code content | ||||
| 
 | ||||
| <ThemeProperty name="codeMultilineMargin" type="@Px int" defaults="Width of the space character" /> | ||||
| <ThemeProperty name="codeMultilineMargin" type="@Px int" defaults="8dip" /> | ||||
| 
 | ||||
| ### Code typeface | ||||
| 
 | ||||
|  | ||||
| @ -108,7 +108,7 @@ public class MarkwonTheme { | ||||
| 
 | ||||
|         final Dip dip = Dip.create(context); | ||||
|         return new Builder() | ||||
|                 .codeMultilineMargin(dip.toPx(8)) | ||||
|                 .codeBlockMargin(dip.toPx(8)) | ||||
|                 .blockMargin(dip.toPx(24)) | ||||
|                 .blockQuoteWidth(dip.toPx(4)) | ||||
|                 .bulletListItemStrokeWidth(dip.toPx(1)) | ||||
| @ -165,15 +165,19 @@ public class MarkwonTheme { | ||||
| 
 | ||||
|     // by default `width` of a space char... it's fun and games, but span doesn't have access to paint in `getLeadingMargin` | ||||
|     // so, we need to set this value explicitly (think of an utility method, that takes TextView/TextPaint and measures space char) | ||||
|     protected final int codeMultilineMargin; | ||||
|     protected final int codeBlockMargin; | ||||
| 
 | ||||
|     // by default Typeface.MONOSPACE | ||||
|     protected final Typeface codeTypeface; | ||||
| 
 | ||||
|     protected final Typeface codeBlockTypeface; | ||||
| 
 | ||||
|     // by default a bit (how much?!) smaller than normal text | ||||
|     // applied ONLY if default typeface was used, otherwise, not applied | ||||
|     protected final int codeTextSize; | ||||
| 
 | ||||
|     protected final int codeBlockTextSize; | ||||
| 
 | ||||
|     // by default paint.getStrokeWidth | ||||
|     protected final int headingBreakHeight; | ||||
| 
 | ||||
| @ -207,9 +211,11 @@ public class MarkwonTheme { | ||||
|         this.codeBlockTextColor = builder.codeBlockTextColor; | ||||
|         this.codeBackgroundColor = builder.codeBackgroundColor; | ||||
|         this.codeBlockBackgroundColor = builder.codeBlockBackgroundColor; | ||||
|         this.codeMultilineMargin = builder.codeMultilineMargin; | ||||
|         this.codeBlockMargin = builder.codeBlockMargin; | ||||
|         this.codeTypeface = builder.codeTypeface; | ||||
|         this.codeBlockTypeface = builder.codeBlockTypeface; | ||||
|         this.codeTextSize = builder.codeTextSize; | ||||
|         this.codeBlockTextSize = builder.codeBlockTextSize; | ||||
|         this.headingBreakHeight = builder.headingBreakHeight; | ||||
|         this.headingBreakColor = builder.headingBreakColor; | ||||
|         this.headingTypeface = builder.headingTypeface; | ||||
| @ -301,66 +307,117 @@ public class MarkwonTheme { | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Modified in 1.0.5 to accept `multiline` argument | ||||
|      * @since 3.0.0 | ||||
|      */ | ||||
|     public void applyCodeTextStyle(@NonNull Paint paint, boolean multiline) { | ||||
|     public void applyCodeTextStyle(@NonNull Paint paint) { | ||||
| 
 | ||||
|         // @since 1.0.5 added handling of multiline code blocks | ||||
|         if (multiline | ||||
|                 && codeBlockTextColor != 0) { | ||||
|             paint.setColor(codeBlockTextColor); | ||||
|         } else if (codeTextColor != 0) { | ||||
|         if (codeTextColor != 0) { | ||||
|             paint.setColor(codeTextColor); | ||||
|         } | ||||
| 
 | ||||
|         // custom typeface was set | ||||
|         if (codeTypeface != null) { | ||||
| 
 | ||||
|             paint.setTypeface(codeTypeface); | ||||
| 
 | ||||
|             // please note that we won't be calculating textSize | ||||
|             // (like we do when no Typeface is provided), if it's some specific typeface | ||||
|             // we would confuse users about textSize | ||||
|             if (codeTextSize != 0) { | ||||
|             if (codeTextSize > 0) { | ||||
|                 paint.setTextSize(codeTextSize); | ||||
|             } | ||||
| 
 | ||||
|         } else { | ||||
| 
 | ||||
|             paint.setTypeface(Typeface.MONOSPACE); | ||||
|             final float textSize; | ||||
|             if (codeTextSize != 0) { | ||||
|                 textSize = codeTextSize; | ||||
| 
 | ||||
|             if (codeTextSize > 0) { | ||||
|                 paint.setTextSize(codeTextSize); | ||||
|             } else { | ||||
|                 textSize = paint.getTextSize() * CODE_DEF_TEXT_SIZE_RATIO; | ||||
|                 paint.setTextSize(paint.getTextSize() * CODE_DEF_TEXT_SIZE_RATIO); | ||||
|             } | ||||
|             paint.setTextSize(textSize); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     public int getCodeMultilineMargin() { | ||||
|         return codeMultilineMargin; | ||||
|     /** | ||||
|      * @since 3.0.0 | ||||
|      */ | ||||
|     public void applyCodeBlockTextStyle(@NonNull Paint paint) { | ||||
| 
 | ||||
|         // apply text color, first check for block specific value, | ||||
|         // then check for code (inline), else do nothing (keep original color of text) | ||||
|         final int textColor = codeBlockTextColor != 0 | ||||
|                 ? codeBlockTextColor | ||||
|                 : codeTextColor; | ||||
| 
 | ||||
|         if (textColor != 0) { | ||||
|             paint.setColor(textColor); | ||||
|         } | ||||
| 
 | ||||
|         final Typeface typeface = codeBlockTypeface != null | ||||
|                 ? codeBlockTypeface | ||||
|                 : codeTypeface; | ||||
| 
 | ||||
|         if (typeface != null) { | ||||
| 
 | ||||
|             paint.setTypeface(typeface); | ||||
| 
 | ||||
|             // please note that we won't be calculating textSize | ||||
|             // (like we do when no Typeface is provided), if it's some specific typeface | ||||
|             // we would confuse users about textSize | ||||
|             final int textSize = codeBlockTextSize > 0 | ||||
|                     ? codeBlockTextSize | ||||
|                     : codeTextSize; | ||||
| 
 | ||||
|             if (textSize > 0) { | ||||
|                 paint.setTextSize(textSize); | ||||
|             } | ||||
|         } else { | ||||
| 
 | ||||
|             // by default use monospace | ||||
|             paint.setTypeface(Typeface.MONOSPACE); | ||||
| 
 | ||||
|             final int textSize = codeBlockTextSize > 0 | ||||
|                     ? codeBlockTextSize | ||||
|                     : codeTextSize; | ||||
| 
 | ||||
|             if (textSize > 0) { | ||||
|                 paint.setTextSize(textSize); | ||||
|             } else { | ||||
|                 // calculate default value | ||||
|                 paint.setTextSize(paint.getTextSize() * CODE_DEF_TEXT_SIZE_RATIO); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|     public int getCodeBlockMargin() { | ||||
|         return codeBlockMargin; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Modified in 1.0.5 to accept `multiline` argument | ||||
|      * @since 3.0.0 | ||||
|      */ | ||||
|     public int getCodeBackgroundColor(@NonNull Paint paint, boolean multiline) { | ||||
| 
 | ||||
|     public int getCodeBackgroundColor(@NonNull Paint paint) { | ||||
|         final int color; | ||||
| 
 | ||||
|         // @since 1.0.5 added handling of multiline code blocks | ||||
|         if (multiline | ||||
|                 && codeBlockBackgroundColor != 0) { | ||||
|             color = codeBlockBackgroundColor; | ||||
|         } else if (codeBackgroundColor != 0) { | ||||
|         if (codeBackgroundColor != 0) { | ||||
|             color = codeBackgroundColor; | ||||
|         } else { | ||||
|             color = ColorUtils.applyAlpha(paint.getColor(), CODE_DEF_BACKGROUND_COLOR_ALPHA); | ||||
|         } | ||||
| 
 | ||||
|         return color; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * @since 3.0.0 | ||||
|      */ | ||||
|     public int getCodeBlockBackgroundColor(@NonNull Paint paint) { | ||||
| 
 | ||||
|         final int color = codeBlockBackgroundColor != 0 | ||||
|                 ? codeBlockBackgroundColor | ||||
|                 : codeBackgroundColor; | ||||
| 
 | ||||
|         return color != 0 | ||||
|                 ? color | ||||
|                 : ColorUtils.applyAlpha(paint.getColor(), CODE_DEF_BACKGROUND_COLOR_ALPHA); | ||||
|     } | ||||
| 
 | ||||
|     public void applyHeadingTextStyle(@NonNull Paint paint, @IntRange(from = 1, to = 6) int level) { | ||||
|         if (headingTypeface == null) { | ||||
|             paint.setFakeBoldText(true); | ||||
| @ -426,9 +483,11 @@ public class MarkwonTheme { | ||||
|         private int codeBlockTextColor; // @since 1.0.5 | ||||
|         private int codeBackgroundColor; | ||||
|         private int codeBlockBackgroundColor; // @since 1.0.5 | ||||
|         private int codeMultilineMargin; | ||||
|         private int codeBlockMargin; | ||||
|         private Typeface codeTypeface; | ||||
|         private Typeface codeBlockTypeface; // @since 3.0.0 | ||||
|         private int codeTextSize; | ||||
|         private int codeBlockTextSize; // @since 3.0.0 | ||||
|         private int headingBreakHeight = -1; | ||||
|         private int headingBreakColor; | ||||
|         private Typeface headingTypeface; | ||||
| @ -451,7 +510,7 @@ public class MarkwonTheme { | ||||
|             this.codeBlockTextColor = theme.codeBlockTextColor; | ||||
|             this.codeBackgroundColor = theme.codeBackgroundColor; | ||||
|             this.codeBlockBackgroundColor = theme.codeBlockBackgroundColor; | ||||
|             this.codeMultilineMargin = theme.codeMultilineMargin; | ||||
|             this.codeBlockMargin = theme.codeBlockMargin; | ||||
|             this.codeTypeface = theme.codeTypeface; | ||||
|             this.codeTextSize = theme.codeTextSize; | ||||
|             this.headingBreakHeight = theme.headingBreakHeight; | ||||
| @ -537,8 +596,8 @@ public class MarkwonTheme { | ||||
|         } | ||||
| 
 | ||||
|         @NonNull | ||||
|         public Builder codeMultilineMargin(@Px int codeMultilineMargin) { | ||||
|             this.codeMultilineMargin = codeMultilineMargin; | ||||
|         public Builder codeBlockMargin(@Px int codeBlockMargin) { | ||||
|             this.codeBlockMargin = codeBlockMargin; | ||||
|             return this; | ||||
|         } | ||||
| 
 | ||||
| @ -548,12 +607,30 @@ public class MarkwonTheme { | ||||
|             return this; | ||||
|         } | ||||
| 
 | ||||
|         /** | ||||
|          * @since 3.0.0 | ||||
|          */ | ||||
|         @NonNull | ||||
|         public Builder codeBlockTypeface(@NonNull Typeface typeface) { | ||||
|             this.codeBlockTypeface = typeface; | ||||
|             return this; | ||||
|         } | ||||
| 
 | ||||
|         @NonNull | ||||
|         public Builder codeTextSize(@Px int codeTextSize) { | ||||
|             this.codeTextSize = codeTextSize; | ||||
|             return this; | ||||
|         } | ||||
| 
 | ||||
|         /** | ||||
|          * @since 3.0.0 | ||||
|          */ | ||||
|         @NonNull | ||||
|         public Builder codeBlockTextSize(@Px int codeTextSize) { | ||||
|             this.codeBlockTextSize = codeTextSize; | ||||
|             return this; | ||||
|         } | ||||
| 
 | ||||
|         @NonNull | ||||
|         public Builder headingBreakHeight(@Px int headingBreakHeight) { | ||||
|             this.headingBreakHeight = headingBreakHeight; | ||||
|  | ||||
| @ -6,12 +6,12 @@ import android.support.annotation.Nullable; | ||||
| import ru.noties.markwon.MarkwonConfiguration; | ||||
| import ru.noties.markwon.RenderProps; | ||||
| import ru.noties.markwon.SpanFactory; | ||||
| import ru.noties.markwon.core.spans.CodeSpan; | ||||
| import ru.noties.markwon.core.spans.CodeBlockSpan; | ||||
| 
 | ||||
| public class CodeBlockSpanFactory implements SpanFactory { | ||||
|     @Nullable | ||||
|     @Override | ||||
|     public Object getSpans(@NonNull MarkwonConfiguration configuration, @NonNull RenderProps props) { | ||||
|         return new CodeSpan(configuration.theme(), true); | ||||
|         return new CodeBlockSpan(configuration.theme()); | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -12,6 +12,6 @@ public class CodeSpanFactory implements SpanFactory { | ||||
|     @Nullable | ||||
|     @Override | ||||
|     public Object getSpans(@NonNull MarkwonConfiguration configuration, @NonNull RenderProps props) { | ||||
|         return new CodeSpan(configuration.theme(), false); | ||||
|         return new CodeSpan(configuration.theme()); | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -0,0 +1,66 @@ | ||||
| package ru.noties.markwon.core.spans; | ||||
| 
 | ||||
| import android.graphics.Canvas; | ||||
| import android.graphics.Paint; | ||||
| import android.graphics.Rect; | ||||
| import android.support.annotation.NonNull; | ||||
| import android.text.Layout; | ||||
| import android.text.TextPaint; | ||||
| import android.text.style.LeadingMarginSpan; | ||||
| import android.text.style.MetricAffectingSpan; | ||||
| 
 | ||||
| import ru.noties.markwon.core.MarkwonTheme; | ||||
| 
 | ||||
| /** | ||||
|  * @since 3.0.0 split inline and block spans | ||||
|  */ | ||||
| public class CodeBlockSpan extends MetricAffectingSpan implements LeadingMarginSpan { | ||||
| 
 | ||||
|     private final MarkwonTheme theme; | ||||
|     private final Rect rect = ObjectsPool.rect(); | ||||
|     private final Paint paint = ObjectsPool.paint(); | ||||
| 
 | ||||
|     public CodeBlockSpan(@NonNull MarkwonTheme theme) { | ||||
|         this.theme = theme; | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void updateMeasureState(TextPaint p) { | ||||
|         apply(p); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void updateDrawState(TextPaint ds) { | ||||
|         apply(ds); | ||||
|     } | ||||
| 
 | ||||
|     private void apply(TextPaint p) { | ||||
|         theme.applyCodeBlockTextStyle(p); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public int getLeadingMargin(boolean first) { | ||||
|         return theme.getCodeBlockMargin(); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void drawLeadingMargin(Canvas c, Paint p, int x, int dir, int top, int baseline, int bottom, CharSequence text, int start, int end, boolean first, Layout layout) { | ||||
| 
 | ||||
|         paint.setStyle(Paint.Style.FILL); | ||||
|         paint.setColor(theme.getCodeBlockBackgroundColor(p)); | ||||
| 
 | ||||
|         final int left; | ||||
|         final int right; | ||||
|         if (dir > 0) { | ||||
|             left = x; | ||||
|             right = c.getWidth(); | ||||
|         } else { | ||||
|             left = x - c.getWidth(); | ||||
|             right = x; | ||||
|         } | ||||
| 
 | ||||
|         rect.set(left, top, right, bottom); | ||||
| 
 | ||||
|         c.drawRect(rect, paint); | ||||
|     } | ||||
| } | ||||
| @ -1,27 +1,20 @@ | ||||
| package ru.noties.markwon.core.spans; | ||||
| 
 | ||||
| import android.graphics.Canvas; | ||||
| import android.graphics.Paint; | ||||
| import android.graphics.Rect; | ||||
| import android.support.annotation.NonNull; | ||||
| import android.text.Layout; | ||||
| import android.text.TextPaint; | ||||
| import android.text.style.LeadingMarginSpan; | ||||
| import android.text.style.MetricAffectingSpan; | ||||
| 
 | ||||
| import ru.noties.markwon.core.MarkwonTheme; | ||||
| 
 | ||||
| public class CodeSpan extends MetricAffectingSpan implements LeadingMarginSpan { | ||||
| /** | ||||
|  * @since 3.0.0 split inline and block spans | ||||
|  */ | ||||
| public class CodeSpan extends MetricAffectingSpan { | ||||
| 
 | ||||
|     private final MarkwonTheme theme; | ||||
|     private final Rect rect = ObjectsPool.rect(); | ||||
|     private final Paint paint = ObjectsPool.paint(); | ||||
| 
 | ||||
|     private final boolean multiline; | ||||
| 
 | ||||
|     public CodeSpan(@NonNull MarkwonTheme theme, boolean multiline) { | ||||
|     public CodeSpan(@NonNull MarkwonTheme theme) { | ||||
|         this.theme = theme; | ||||
|         this.multiline = multiline; | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
| @ -32,41 +25,10 @@ public class CodeSpan extends MetricAffectingSpan implements LeadingMarginSpan { | ||||
|     @Override | ||||
|     public void updateDrawState(TextPaint ds) { | ||||
|         apply(ds); | ||||
|         if (!multiline) { | ||||
|             ds.bgColor = theme.getCodeBackgroundColor(ds, false); | ||||
|         } | ||||
|         ds.bgColor = theme.getCodeBackgroundColor(ds); | ||||
|     } | ||||
| 
 | ||||
|     private void apply(TextPaint p) { | ||||
|         theme.applyCodeTextStyle(p, multiline); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public int getLeadingMargin(boolean first) { | ||||
|         return multiline ? theme.getCodeMultilineMargin() : 0; | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void drawLeadingMargin(Canvas c, Paint p, int x, int dir, int top, int baseline, int bottom, CharSequence text, int start, int end, boolean first, Layout layout) { | ||||
| 
 | ||||
|         if (multiline) { | ||||
| 
 | ||||
|             paint.setStyle(Paint.Style.FILL); | ||||
|             paint.setColor(theme.getCodeBackgroundColor(p, true)); | ||||
| 
 | ||||
|             final int left; | ||||
|             final int right; | ||||
|             if (dir > 0) { | ||||
|                 left = x; | ||||
|                 right = c.getWidth(); | ||||
|             } else { | ||||
|                 left = x - c.getWidth(); | ||||
|                 right = x; | ||||
|             } | ||||
| 
 | ||||
|             rect.set(left, top, right, bottom); | ||||
| 
 | ||||
|             c.drawRect(rect, paint); | ||||
|         } | ||||
|         theme.applyCodeTextStyle(p); | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -13,8 +13,6 @@ import android.text.TextUtils; | ||||
| import org.commonmark.ext.gfm.tables.TableBlock; | ||||
| import org.commonmark.ext.gfm.tables.TablesExtension; | ||||
| import org.commonmark.node.FencedCodeBlock; | ||||
| import org.commonmark.node.Heading; | ||||
| import org.commonmark.node.SoftLineBreak; | ||||
| import org.commonmark.parser.Parser; | ||||
| 
 | ||||
| import java.io.BufferedReader; | ||||
| @ -29,9 +27,7 @@ import ru.noties.markwon.AbstractMarkwonPlugin; | ||||
| import ru.noties.markwon.Markwon; | ||||
| import ru.noties.markwon.MarkwonConfiguration; | ||||
| import ru.noties.markwon.MarkwonVisitor; | ||||
| import ru.noties.markwon.SpanFactory; | ||||
| import ru.noties.markwon.core.CorePlugin; | ||||
| import ru.noties.markwon.core.CoreProps; | ||||
| import ru.noties.markwon.html.HtmlPlugin; | ||||
| import ru.noties.markwon.image.ImagesPlugin; | ||||
| import ru.noties.markwon.image.svg.SvgPlugin; | ||||
| @ -52,36 +48,6 @@ public class RecyclerActivity extends Activity { | ||||
|         super.onCreate(savedInstanceState); | ||||
|         setContentView(R.layout.activity_recycler); | ||||
| 
 | ||||
|         { | ||||
| final Markwon markwon = Markwon.builder(contex) | ||||
|         .usePlugin(new AbstractMarkwonPlugin() { | ||||
| @Override | ||||
| public void configureVisitor(@NonNull MarkwonVisitor.Builder builder) { | ||||
|     builder.on(Heading.class, new MarkwonVisitor.NodeVisitor<Heading>() { | ||||
|         @Override | ||||
|         public void visit(@NonNull MarkwonVisitor visitor, @NonNull Heading heading) { | ||||
| 
 | ||||
|             // or just `visitor.length()` | ||||
|             final int start = visitor.builder().length(); | ||||
| 
 | ||||
|             visitor.visitChildren(heading); | ||||
| 
 | ||||
|             // or just `visitor.setSpansForNodeOptional(heading, start)` | ||||
|             final SpanFactory factory = visitor.configuration().spansFactory().get(heading.getClass()); | ||||
|             if (factory != null) { | ||||
|                 visitor.setSpans(start, factory.getSpans(visitor.configuration(), visitor.renderProps())); | ||||
|             } | ||||
| 
 | ||||
|             if (visitor.hasNext(heading)) { | ||||
|                 visitor.ensureNewLine(); | ||||
|                 visitor.forceNewLine(); | ||||
|             } | ||||
|         } | ||||
|     }); | ||||
| } | ||||
|         }); | ||||
|         } | ||||
| 
 | ||||
|         // create MarkwonAdapter and register two blocks that will be rendered differently | ||||
|         // * fenced code block (can also specify the same Entry for indended code block) | ||||
|         // * table block | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Dimitry Ivanov
						Dimitry Ivanov