Skip to content

Commit

Permalink
feat: make it possible to create a custom Markdown code theme (#4343)
Browse files Browse the repository at this point in the history
* parseMarkdownCodeTheme util

* MarkdownCustomCodeTheme dataclass

* enhance the handling of special cases
  • Loading branch information
ndonkoHenri authored Nov 13, 2024
1 parent 4fb3cc1 commit 5fb877b
Show file tree
Hide file tree
Showing 4 changed files with 103 additions and 18 deletions.
10 changes: 5 additions & 5 deletions packages/flet/lib/src/controls/markdown.dart
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import 'dart:convert';

import 'package:flutter/material.dart';
import 'package:flutter_highlight/theme_map.dart';
import 'package:flutter_markdown/flutter_markdown.dart';
import 'package:markdown/markdown.dart' as md;

Expand Down Expand Up @@ -63,6 +62,8 @@ class MarkdownControl extends StatelessWidget with FletStoreMixin {
.copyWith(fontFamily: "monospace"));
var mdStyleSheet = parseMarkdownStyleSheet(
control, "mdStyleSheet", Theme.of(context), pageArgs);
var codeTheme =
parseMarkdownCodeTheme(control, "codeTheme", Theme.of(context));
Widget markdown = MarkdownBody(
data: value,
selectable: selectable,
Expand All @@ -71,8 +72,7 @@ class MarkdownControl extends StatelessWidget with FletStoreMixin {
: getBaseUri(pageArgs.pageUri!).toString(),
extensionSet: extensionSet,
builders: {
'code': CodeElementBuilder(
codeTheme.toLowerCase(), codeStyleSheet, selectable),
'code': CodeElementBuilder(codeTheme, codeStyleSheet, selectable),
},
styleSheet: mdStyleSheet,
imageBuilder: (Uri uri, String? title, String? alt) {
Expand Down Expand Up @@ -142,7 +142,7 @@ class MarkdownControl extends StatelessWidget with FletStoreMixin {
}

class CodeElementBuilder extends MarkdownElementBuilder {
final String codeTheme;
final Map<String, TextStyle> codeTheme;
final MarkdownStyleSheet mdStyleSheet;
final bool selectable;

Expand Down Expand Up @@ -175,7 +175,7 @@ class CodeElementBuilder extends MarkdownElementBuilder {

// Specify highlight theme
// All available themes are listed in `themes` folder
theme: themeMap[codeTheme] ?? {},
theme: codeTheme,

// Specify padding
padding: mdStyleSheet.codeblockPadding,
Expand Down
55 changes: 44 additions & 11 deletions packages/flet/lib/src/utils/markdown.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import 'dart:convert';

import 'package:flutter/material.dart';
import 'package:flutter_highlight/theme_map.dart';
import 'package:flutter_markdown/flutter_markdown.dart';
import 'package:markdown/markdown.dart' as md;

Expand Down Expand Up @@ -29,19 +30,51 @@ md.ExtensionSet? parseMarkdownExtensionSet(String? value,
}
}

Map<String, TextStyle> parseMarkdownCodeTheme(
Control control,
String propName,
ThemeData theme,
) {
final v = control.attrString(propName);
if (v == null) {
return {};
}
dynamic j = json.decode(v);
if (j is String) {
return themeMap[j.toLowerCase()] ?? {};
} else if (j is Map<String, dynamic>) {
String transformKey(String key) {
switch (key) {
case 'class_name':
return 'class';
case 'built_in':
return key;
default:
return key.replaceAll('_', '-');
}
}

final resultMap =
j.map((key, value) => MapEntry(key, textStyleFromJson(theme, value)));
resultMap.removeWhere(
(key, value) => value == null); // remove entries with null values
return resultMap.map((key, value) => MapEntry(transformKey(key), value!));
}
return {};
}

MarkdownStyleSheet? parseMarkdownStyleSheet(Control control, String propName,
ThemeData theme, PageArgsModel? pageArgs) {
dynamic j;
var v = control.attrString(propName, null);
var v = control.attrString(propName);
if (v == null) {
return null;
}
j = json.decode(v);
dynamic j = json.decode(v);
return markdownStyleSheetFromJson(theme, j, pageArgs);
}

MarkdownStyleSheet markdownStyleSheetFromJson(ThemeData theme,
Map<String, dynamic> j, PageArgsModel? pageArgs) {
MarkdownStyleSheet markdownStyleSheetFromJson(
ThemeData theme, Map<String, dynamic> j, PageArgsModel? pageArgs) {
TextStyle? parseTextStyle(String propName) {
return j[propName] != null ? textStyleFromJson(theme, j[propName]) : null;
}
Expand Down Expand Up @@ -119,13 +152,13 @@ MarkdownStyleSheet markdownStyleSheetFromJson(ThemeData theme,
horizontalRuleDecoration: boxDecorationFromJSON(
theme, j["horizontal_rule_decoration"], pageArgs) ??
BoxDecoration(
border: Border(
top: BorderSide(
width: 5.0,
color: theme.dividerColor,
),
),
border: Border(
top: BorderSide(
width: 5.0,
color: theme.dividerColor,
),
),
),
blockquoteAlign:
parseWrapAlignment(j["blockquote_alignment"], WrapAlignment.start)!,
codeblockAlign:
Expand Down
1 change: 1 addition & 0 deletions sdk/python/packages/flet/src/flet/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,7 @@
from flet.core.markdown import (
Markdown,
MarkdownCodeTheme,
MarkdownCustomCodeTheme,
MarkdownExtensionSet,
MarkdownSelectionChangeCause,
MarkdownSelectionChangeEvent,
Expand Down
55 changes: 53 additions & 2 deletions sdk/python/packages/flet/src/flet/core/markdown.py
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,57 @@ class MarkdownCodeTheme(Enum):
ZENBURN = "zenburn"


@dataclass
class MarkdownCustomCodeTheme:
addition: Optional[TextStyle] = None
attr: Optional[TextStyle] = None
attribute: Optional[TextStyle] = None
built_in: Optional[TextStyle] = None
builtin_name: Optional[TextStyle] = None
bullet: Optional[TextStyle] = None
class_name: Optional[TextStyle] = None
code: Optional[TextStyle] = None
comment: Optional[TextStyle] = None
deletion: Optional[TextStyle] = None
doctag: Optional[TextStyle] = None
emphasis: Optional[TextStyle] = None
formula: Optional[TextStyle] = None
function: Optional[TextStyle] = None
keyword: Optional[TextStyle] = None
link: Optional[TextStyle] = None
link_label: Optional[TextStyle] = None
literal: Optional[TextStyle] = None
meta: Optional[TextStyle] = None
meta_keyword: Optional[TextStyle] = None
meta_string: Optional[TextStyle] = None
name: Optional[TextStyle] = None
number: Optional[TextStyle] = None
operator: Optional[TextStyle] = None
params: Optional[TextStyle] = None
pattern_match: Optional[TextStyle] = None
quote: Optional[TextStyle] = None
regexp: Optional[TextStyle] = None
root: Optional[TextStyle] = None
section: Optional[TextStyle] = None
selector_attr: Optional[TextStyle] = None
selector_class: Optional[TextStyle] = None
selector_id: Optional[TextStyle] = None
selector_pseudo: Optional[TextStyle] = None
selector_tag: Optional[TextStyle] = None
string: Optional[TextStyle] = None
strong: Optional[TextStyle] = None
stronge: Optional[TextStyle] = None
subst: Optional[TextStyle] = None
subtr: Optional[TextStyle] = None
symbol: Optional[TextStyle] = None
tag: Optional[TextStyle] = None
template_tag: Optional[TextStyle] = None
template_variable: Optional[TextStyle] = None
title: Optional[TextStyle] = None
type: Optional[TextStyle] = None
variable: Optional[TextStyle] = None


class Markdown(ConstrainedControl):
"""
Control for rendering text in markdown format.
Expand All @@ -239,7 +290,7 @@ def __init__(
value: Optional[str] = None,
selectable: Optional[bool] = None,
extension_set: Optional[MarkdownExtensionSet] = None,
code_theme: Optional[MarkdownCodeTheme] = None,
code_theme: Optional[Union[MarkdownCodeTheme, MarkdownCustomCodeTheme]] = None,
code_style: Optional[TextStyle] = None,
auto_follow_links: Optional[bool] = None,
shrink_wrap: Optional[bool] = None,
Expand Down Expand Up @@ -349,6 +400,7 @@ def before_update(self):
self._set_attr_json("codeStyle", self.__code_style)
self._set_attr_json("codeStyleSheet", self.__code_style_sheet)
self._set_attr_json("mdStyleSheet", self.__md_style_sheet)
self._set_attr_json("codeTheme", self.__code_theme)

def _get_children(self):
if self.__img_error_content is not None:
Expand Down Expand Up @@ -437,7 +489,6 @@ def code_theme(self) -> Optional[MarkdownCodeTheme]:
@code_theme.setter
def code_theme(self, value: Optional[MarkdownCodeTheme]):
self.__code_theme = value
self._set_enum_attr("codeTheme", value, MarkdownCodeTheme)

# code_style
@property
Expand Down

0 comments on commit 5fb877b

Please sign in to comment.