zig-codeblocks
Advanced tools
| from zig_codeblocks.styling import Color, Style, Theme | ||
| KEYWORDS = frozenset( | ||
| { | ||
| "addrspace", | ||
| "align", | ||
| "allowzero", | ||
| "and", | ||
| "anyframe", | ||
| "anytype", | ||
| "asm", | ||
| "async", | ||
| "await", | ||
| "break", | ||
| "callconv", | ||
| "catch", | ||
| "comptime", | ||
| "const", | ||
| "continue", | ||
| "defer", | ||
| "else", | ||
| "enum", | ||
| "errdefer", | ||
| "error", | ||
| "export", | ||
| "extern", | ||
| "fn", | ||
| "for", | ||
| "if", | ||
| "inline", | ||
| "linksection", | ||
| "noalias", | ||
| "noinline", | ||
| "nosuspend", | ||
| "opaque", | ||
| "or", | ||
| "orelse", | ||
| "packed", | ||
| "pub", | ||
| "resume", | ||
| "return", | ||
| "struct", | ||
| "suspend", | ||
| "switch", | ||
| "test", | ||
| "threadlocal", | ||
| "try", | ||
| "union", | ||
| "unreachable", | ||
| "usingnamespace", | ||
| "var", | ||
| "volatile", | ||
| "while", | ||
| } | ||
| ) | ||
| IDENTIFIERS = frozenset({"identifier", "c"}) | ||
| NUMERIC_LITERALS = frozenset({"integer", "float"}) | ||
| PRIMITIVE_VALUES = frozenset({"true", "false", "null", "undefined"}) | ||
| TYPES = frozenset( | ||
| { | ||
| "anyerror", | ||
| "anyopaque", | ||
| "bool", | ||
| "builtin_type", | ||
| "c_char", | ||
| "c_int", | ||
| "c_long", | ||
| "c_longdouble", | ||
| "c_longlong", | ||
| "c_short", | ||
| "c_uint", | ||
| "c_ulong", | ||
| "c_ulonglong", | ||
| "c_ushort", | ||
| "comptime_float", | ||
| "comptime_int", | ||
| "f128", | ||
| "f16", | ||
| "f32", | ||
| "f64", | ||
| "f80", | ||
| "isize", | ||
| "noreturn", | ||
| "type", | ||
| "usize", | ||
| "void", | ||
| } | ||
| ) | ||
| STRINGLIKE = frozenset( | ||
| {"string_content", "multiline_string", '"', "'", "character_content"} | ||
| ) | ||
| DEFAULT_THEME = Theme( | ||
| builtin_identifiers=Style(Color.BLUE, bold=True), | ||
| calls=Style(Color.BLUE), | ||
| comments=Style(Color.GRAY), | ||
| keywords=Style(Color.MAGENTA), | ||
| numeric=Style(Color.CYAN), | ||
| primitive_values=Style(Color.CYAN), | ||
| strings=Style(Color.GREEN), | ||
| types=Style(Color.ORANGE), | ||
| ) |
+12
-0
@@ -8,2 +8,13 @@ # Changelog | ||
| ## [v0.2.0] - 2025-02-09 | ||
| ### Added | ||
| - Theming support | ||
| - Improved reset code insertion | ||
| - Improved type highlighting | ||
| - Primitive value highlighting (i.e. `true`, `false`, `null`, `undefined`) | ||
| ### Changed | ||
| - Swapped keyword and type colors in the default theme | ||
| ## [v0.1.2] - 2025-02-09 | ||
@@ -34,1 +45,2 @@ | ||
| [v0.1.2]: https://github.com/trag1c/ixia/compare/v0.1.1...v0.1.2 | ||
| [v0.2.0]: https://github.com/trag1c/ixia/compare/v0.1.2...v0.2.0 |
+105
-9
| Metadata-Version: 2.4 | ||
| Name: zig-codeblocks | ||
| Version: 0.1.2 | ||
| Version: 0.2.0 | ||
| Summary: Zig ANSI syntax highlighting library | ||
@@ -20,4 +20,5 @@ Project-URL: repository, https://github.com/trag1c/zig-codeblocks | ||
| `zig-codeblocks` is a CPython 3.10+ library for adding syntax highlighting to | ||
| Zig code blocks in Markdown files through ANSI escape codes. Originally intended | ||
| for patching the lack of syntax highlighting for Zig on Discord. | ||
| Zig code blocks in Markdown files through ANSI escape codes. | ||
| Originally intended for patching the lack of syntax highlighting for Zig on | ||
| Discord. | ||
@@ -40,5 +41,6 @@ | ||
| ```py | ||
| def extract_codeblocks(source: str) -> Iterator[Codeblock] | ||
| def extract_codeblocks(source: str | bytes) -> Iterator[CodeBlock] | ||
| ``` | ||
| Yields [`CodeBlock`](#codeblock)s from a Markdown source. | ||
| Assumes UTF-8 if source is `bytes`. | ||
@@ -72,5 +74,8 @@ **Example usage:** | ||
| ```py | ||
| def highlight_zig_code(source: str) -> str | ||
| def highlight_zig_code(source: str | bytes, theme: Theme = DEFAULT_THEME) -> str | ||
| ``` | ||
| Returns an ANSI syntax-highlighted version of the given Zig source code. | ||
| Assumes UTF-8 if source is `bytes`. | ||
| An optional [`Theme`](#theme) can be supplied (defaults to | ||
| [`DEFAULT_THEME`](#default_theme)). | ||
@@ -81,8 +86,18 @@ **Example usage:** | ||
| from zig_codeblocks import highlight_zig_code | ||
| from zig_codeblocks import DEFAULT_THEME, Color, Style, highlight_zig_code | ||
| source = Path("examples/hello_world.zig").read_text() | ||
| print(highlight_zig_code(source)) | ||
| theme = DEFAULT_THEME.copy() | ||
| theme.builtin_identifiers = Style(Color.ORANGE, underline=True) | ||
| theme.strings = Style(Color.CYAN) | ||
| theme.types = None | ||
| print( | ||
| highlight_zig_code(source), | ||
| highlight_zig_code(source, theme), | ||
| sep="\n\n", | ||
| ) | ||
| ``` | ||
| <img src="examples/highlighted-zig-code.png" width="55%"> | ||
| <img src="examples/highlighted-zig-code.png" width="65%"> | ||
@@ -92,5 +107,13 @@ | ||
| ```py | ||
| def process_markdown(source: str, *, only_code: bool = False) -> str | ||
| def process_markdown( | ||
| source: str | bytes, | ||
| theme: Theme = DEFAULT_THEME, | ||
| *, | ||
| only_code: bool = False, | ||
| ) -> str | ||
| ``` | ||
| Returns a Markdown source with Zig code blocks syntax-highlighted. | ||
| Assumes UTF-8 if source is `bytes`. | ||
| An optional [`Theme`](#theme) can be supplied (defaults to | ||
| [`DEFAULT_THEME`](#default_theme)). | ||
| If `only_code` is True, only processed Zig code blocks will be returned. | ||
@@ -119,2 +142,75 @@ | ||
| ### `Color` | ||
| ```py | ||
| class Color(Enum): | ||
| GRAY = "30" | ||
| RED = "31" | ||
| GREEN = "32" | ||
| ORANGE = "33" | ||
| BLUE = "34" | ||
| MAGENTA = "35" | ||
| CYAN = "36" | ||
| WHITE = "37" # Black for light mode | ||
| ``` | ||
| An enumeration of 3-bit ANSI colors. | ||
| Some names were adjusted to match Discord's style. | ||
| ### `Style` | ||
| ```py | ||
| @dataclass(slots=True, frozen=True) | ||
| class Style: | ||
| color: Color | ||
| _: KW_ONLY | ||
| bold: bool = False | ||
| underline: bool = False | ||
| ``` | ||
| A style for syntax highlighting. | ||
| Takes a [`Color`](#color) and can optionally be bold and/or underlined. | ||
| Immutable. | ||
| Produces an SGR sequence when converted to a string. | ||
| ### `Theme` | ||
| ```py | ||
| @dataclass(slots=True, kw_only=True) | ||
| class Theme: | ||
| builtin_identifiers: Style | None = None | ||
| calls: Style | None = None | ||
| comments: Style | None = None | ||
| identifiers: Style | None = None | ||
| keywords: Style | None = None | ||
| numeric: Style | None = None | ||
| strings: Style | None = None | ||
| primitive_values: Style | None = None | ||
| types: Style | None = None | ||
| ``` | ||
| A theme for syntax highlighting Zig code. | ||
| Each field is optional and can be provided a [`Style`](#style) to apply to the | ||
| corresponding token type. | ||
| #### `Theme.copy` | ||
| ```py | ||
| def copy(self) -> Theme | ||
| ``` | ||
| Returns a copy of the theme. | ||
| ### `DEFAULT_THEME` | ||
| The default theme used for highlighting, defined as follows: | ||
| ```py | ||
| DEFAULT_THEME = Theme( | ||
| builtin_identifiers=Style(Color.BLUE, bold=True), | ||
| calls=Style(Color.BLUE), | ||
| comments=Style(Color.GRAY), | ||
| identifiers=None, | ||
| keywords=Style(Color.MAGENTA), | ||
| numeric=Style(Color.CYAN), | ||
| primitive_values=Style(Color.CYAN), | ||
| strings=Style(Color.GREEN), | ||
| types=Style(Color.ORANGE), | ||
| ) | ||
| ``` | ||
| ## License | ||
@@ -121,0 +217,0 @@ `zig-codeblocks` is licensed under the [MIT License]. |
+1
-1
| [project] | ||
| name = "zig-codeblocks" | ||
| version = "0.1.2" | ||
| version = "0.2.0" | ||
| description = "Zig ANSI syntax highlighting library" | ||
@@ -5,0 +5,0 @@ readme = "README.md" |
+104
-8
@@ -7,4 +7,5 @@ [](https://github.com/astral-sh/uv) | ||
| `zig-codeblocks` is a CPython 3.10+ library for adding syntax highlighting to | ||
| Zig code blocks in Markdown files through ANSI escape codes. Originally intended | ||
| for patching the lack of syntax highlighting for Zig on Discord. | ||
| Zig code blocks in Markdown files through ANSI escape codes. | ||
| Originally intended for patching the lack of syntax highlighting for Zig on | ||
| Discord. | ||
@@ -27,5 +28,6 @@ | ||
| ```py | ||
| def extract_codeblocks(source: str) -> Iterator[Codeblock] | ||
| def extract_codeblocks(source: str | bytes) -> Iterator[CodeBlock] | ||
| ``` | ||
| Yields [`CodeBlock`](#codeblock)s from a Markdown source. | ||
| Assumes UTF-8 if source is `bytes`. | ||
@@ -59,5 +61,8 @@ **Example usage:** | ||
| ```py | ||
| def highlight_zig_code(source: str) -> str | ||
| def highlight_zig_code(source: str | bytes, theme: Theme = DEFAULT_THEME) -> str | ||
| ``` | ||
| Returns an ANSI syntax-highlighted version of the given Zig source code. | ||
| Assumes UTF-8 if source is `bytes`. | ||
| An optional [`Theme`](#theme) can be supplied (defaults to | ||
| [`DEFAULT_THEME`](#default_theme)). | ||
@@ -68,8 +73,18 @@ **Example usage:** | ||
| from zig_codeblocks import highlight_zig_code | ||
| from zig_codeblocks import DEFAULT_THEME, Color, Style, highlight_zig_code | ||
| source = Path("examples/hello_world.zig").read_text() | ||
| print(highlight_zig_code(source)) | ||
| theme = DEFAULT_THEME.copy() | ||
| theme.builtin_identifiers = Style(Color.ORANGE, underline=True) | ||
| theme.strings = Style(Color.CYAN) | ||
| theme.types = None | ||
| print( | ||
| highlight_zig_code(source), | ||
| highlight_zig_code(source, theme), | ||
| sep="\n\n", | ||
| ) | ||
| ``` | ||
| <img src="examples/highlighted-zig-code.png" width="55%"> | ||
| <img src="examples/highlighted-zig-code.png" width="65%"> | ||
@@ -79,5 +94,13 @@ | ||
| ```py | ||
| def process_markdown(source: str, *, only_code: bool = False) -> str | ||
| def process_markdown( | ||
| source: str | bytes, | ||
| theme: Theme = DEFAULT_THEME, | ||
| *, | ||
| only_code: bool = False, | ||
| ) -> str | ||
| ``` | ||
| Returns a Markdown source with Zig code blocks syntax-highlighted. | ||
| Assumes UTF-8 if source is `bytes`. | ||
| An optional [`Theme`](#theme) can be supplied (defaults to | ||
| [`DEFAULT_THEME`](#default_theme)). | ||
| If `only_code` is True, only processed Zig code blocks will be returned. | ||
@@ -106,2 +129,75 @@ | ||
| ### `Color` | ||
| ```py | ||
| class Color(Enum): | ||
| GRAY = "30" | ||
| RED = "31" | ||
| GREEN = "32" | ||
| ORANGE = "33" | ||
| BLUE = "34" | ||
| MAGENTA = "35" | ||
| CYAN = "36" | ||
| WHITE = "37" # Black for light mode | ||
| ``` | ||
| An enumeration of 3-bit ANSI colors. | ||
| Some names were adjusted to match Discord's style. | ||
| ### `Style` | ||
| ```py | ||
| @dataclass(slots=True, frozen=True) | ||
| class Style: | ||
| color: Color | ||
| _: KW_ONLY | ||
| bold: bool = False | ||
| underline: bool = False | ||
| ``` | ||
| A style for syntax highlighting. | ||
| Takes a [`Color`](#color) and can optionally be bold and/or underlined. | ||
| Immutable. | ||
| Produces an SGR sequence when converted to a string. | ||
| ### `Theme` | ||
| ```py | ||
| @dataclass(slots=True, kw_only=True) | ||
| class Theme: | ||
| builtin_identifiers: Style | None = None | ||
| calls: Style | None = None | ||
| comments: Style | None = None | ||
| identifiers: Style | None = None | ||
| keywords: Style | None = None | ||
| numeric: Style | None = None | ||
| strings: Style | None = None | ||
| primitive_values: Style | None = None | ||
| types: Style | None = None | ||
| ``` | ||
| A theme for syntax highlighting Zig code. | ||
| Each field is optional and can be provided a [`Style`](#style) to apply to the | ||
| corresponding token type. | ||
| #### `Theme.copy` | ||
| ```py | ||
| def copy(self) -> Theme | ||
| ``` | ||
| Returns a copy of the theme. | ||
| ### `DEFAULT_THEME` | ||
| The default theme used for highlighting, defined as follows: | ||
| ```py | ||
| DEFAULT_THEME = Theme( | ||
| builtin_identifiers=Style(Color.BLUE, bold=True), | ||
| calls=Style(Color.BLUE), | ||
| comments=Style(Color.GRAY), | ||
| identifiers=None, | ||
| keywords=Style(Color.MAGENTA), | ||
| numeric=Style(Color.CYAN), | ||
| primitive_values=Style(Color.CYAN), | ||
| strings=Style(Color.GREEN), | ||
| types=Style(Color.ORANGE), | ||
| ) | ||
| ``` | ||
| ## License | ||
@@ -108,0 +204,0 @@ `zig-codeblocks` is licensed under the [MIT License]. |
@@ -0,4 +1,15 @@ | ||
| from zig_codeblocks.consts import DEFAULT_THEME | ||
| from zig_codeblocks.formatting import highlight_zig_code, process_markdown | ||
| from zig_codeblocks.parsing import CodeBlock, extract_codeblocks | ||
| from zig_codeblocks.styling import Color, Style, Theme | ||
| __all__ = ("CodeBlock", "extract_codeblocks", "highlight_zig_code", "process_markdown") | ||
| __all__ = ( | ||
| "DEFAULT_THEME", | ||
| "CodeBlock", | ||
| "Color", | ||
| "Style", | ||
| "Theme", | ||
| "extract_codeblocks", | ||
| "highlight_zig_code", | ||
| "process_markdown", | ||
| ) |
@@ -6,4 +6,5 @@ from __future__ import annotations | ||
| from zig_codeblocks import consts | ||
| from zig_codeblocks.parsing import extract_codeblocks, tokenize_zig | ||
| from zig_codeblocks.styling import Color, Reset, Style | ||
| from zig_codeblocks.styling import Reset, Style, Theme | ||
@@ -18,80 +19,21 @@ if TYPE_CHECKING: | ||
| ZIG_KEYWORDS = frozenset( | ||
| { | ||
| "addrspace", | ||
| "align", | ||
| "allowzero", | ||
| "and", | ||
| "anyframe", | ||
| "anytype", | ||
| "asm", | ||
| "async", | ||
| "await", | ||
| "break", | ||
| "callconv", | ||
| "catch", | ||
| "comptime", | ||
| "const", | ||
| "continue", | ||
| "defer", | ||
| "else", | ||
| "enum", | ||
| "errdefer", | ||
| "error", | ||
| "export", | ||
| "extern", | ||
| "fn", | ||
| "for", | ||
| "if", | ||
| "inline", | ||
| "linksection", | ||
| "noalias", | ||
| "noinline", | ||
| "nosuspend", | ||
| "opaque", | ||
| "or", | ||
| "orelse", | ||
| "packed", | ||
| "pub", | ||
| "resume", | ||
| "return", | ||
| "struct", | ||
| "suspend", | ||
| "switch", | ||
| "test", | ||
| "threadlocal", | ||
| "try", | ||
| "union", | ||
| "unreachable", | ||
| "usingnamespace", | ||
| "var", | ||
| "volatile", | ||
| "while", | ||
| } | ||
| ) | ||
| ZIG_TYPE_TOKENS = frozenset({"builtin_type", "f64"}) | ||
| ZIG_NUMERIC_TOKENS = frozenset({"integer", "float"}) | ||
| ZIG_STRING_TOKENS = frozenset( | ||
| {"string_content", "multiline_string", '"', "'", "character_content"} | ||
| ) | ||
| _KIND_MAPPINGS = { | ||
| "comment": Style(Color.GRAY), | ||
| "builtin_identifier": Style(Color.BLUE, bold=True), | ||
| } | ||
| _GROUP_KIND_MAPPINGS: tuple[tuple[frozenset[str], Style], ...] = ( | ||
| (ZIG_STRING_TOKENS, Style(Color.GREEN)), | ||
| (ZIG_KEYWORDS, Style(Color.ORANGE)), | ||
| (ZIG_NUMERIC_TOKENS, Style(Color.CYAN)), | ||
| (ZIG_TYPE_TOKENS, Style(Color.MAGENTA)), | ||
| ) | ||
| def _get_style(kind: str, theme: Theme) -> Style | None: | ||
| for options, style in ( | ||
| (consts.IDENTIFIERS, theme.identifiers), | ||
| (consts.KEYWORDS, theme.keywords), | ||
| (consts.NUMERIC_LITERALS, theme.numeric), | ||
| (consts.PRIMITIVE_VALUES, theme.primitive_values), | ||
| (consts.STRINGLIKE, theme.strings), | ||
| (consts.TYPES, theme.types), | ||
| ): | ||
| if kind in options: | ||
| return style | ||
| if kind == "comment": | ||
| return theme.comments | ||
| if kind == "builtin_identifier": | ||
| return theme.builtin_identifiers | ||
| return None | ||
| def _get_style(kind: str) -> Style | None: | ||
| return next( | ||
| (style for options, style in _GROUP_KIND_MAPPINGS if kind in options), | ||
| None, | ||
| ) or _KIND_MAPPINGS.get(kind) | ||
| def _peek(iterator: Iterator[T]) -> T: | ||
@@ -105,11 +47,3 @@ return next(tee(iterator, 1)[0]) | ||
| def _adjust_reset(body: Body) -> None: | ||
| last_style = _last_applied_style(body) | ||
| if last_style is Reset.BOLD: | ||
| body[~body[::-1].index(Reset.BOLD)] = Reset.FULL | ||
| elif last_style is not Reset.FULL: | ||
| body.append(Reset.FULL) | ||
| def _adjust_string_idents(body: Body, token: Token) -> None: | ||
| def _adjust_string_idents(body: Body, token: Token, theme: Theme) -> None: | ||
| # Special case for `whatever.@"something here"`, | ||
@@ -119,10 +53,15 @@ # which is an identifier, so should have no string highlighting | ||
| token.kind == '"' | ||
| and _last_applied_style(body) == Style(Color.GREEN) | ||
| and _last_applied_style(body) == theme.strings | ||
| and len(body) > 3 | ||
| and body[-4] == "@" | ||
| ): | ||
| del body[-3] | ||
| if theme.identifiers: | ||
| body[-3] = theme.identifiers | ||
| else: | ||
| del body[-3] | ||
| def _process_zig_tokens(source: bytes, tokens: Iterator[Token]) -> str: | ||
| def _process_zig_tokens( | ||
| source: bytes, tokens: Iterator[Token], theme: Theme = consts.DEFAULT_THEME | ||
| ) -> str: | ||
| body: Body = [] | ||
@@ -135,4 +74,5 @@ pointer = 0 | ||
| filler = source[pointer : token.byte_range.start] | ||
| if not filler.isspace(): | ||
| _adjust_reset(body) | ||
| match filler.isspace(), _last_applied_style(body): | ||
| case (False, _) | (True, Style(underline=True) | Style(bold=True)): | ||
| body.append(Reset.FULL) | ||
| body.append(filler.decode()) | ||
@@ -147,21 +87,16 @@ pointer = token.byte_range.start | ||
| style = ( | ||
| Style(Color.BLUE) # Special case for function calls | ||
| theme.calls | ||
| if token.kind == "identifier" and _peek(tokens).kind == "(" | ||
| else _get_style(token.kind) | ||
| else _get_style(token.kind, theme) | ||
| ) | ||
| if style is None: | ||
| _adjust_reset(body) | ||
| if _last_applied_style(body) is not Reset.FULL: | ||
| body.append(Reset.FULL) | ||
| elif _last_applied_style(body) is not style: | ||
| body.append(style) | ||
| _adjust_string_idents(body, token) | ||
| _adjust_string_idents(body, token, theme) | ||
| body.append(token.value.decode()) | ||
| match style: | ||
| case Style(bold=True): | ||
| body.append(Reset.BOLD) | ||
| case Style(underline=True): | ||
| body.append(Reset.UNDERLINE) | ||
| pointer = token.byte_range.stop | ||
@@ -175,3 +110,3 @@ try: | ||
| def highlight_zig_code(source: str | bytes) -> str: | ||
| def highlight_zig_code(source: str | bytes, theme: Theme = consts.DEFAULT_THEME) -> str: | ||
| """ | ||
@@ -183,6 +118,8 @@ Return an ANSI syntax-highlighted version of the given Zig source code. | ||
| source = source.encode() | ||
| return _process_zig_tokens(source, tokenize_zig(source)) | ||
| return _process_zig_tokens(source, tokenize_zig(source), theme) | ||
| def process_markdown(source: str | bytes, *, only_code: bool = False) -> str: | ||
| def process_markdown( | ||
| source: str | bytes, theme: Theme = consts.DEFAULT_THEME, *, only_code: bool = False | ||
| ) -> str: | ||
| """ | ||
@@ -200,8 +137,9 @@ Return a Markdown source with Zig code blocks syntax-highlighted. | ||
| return "\n".join( | ||
| f"```ansi\n{highlight_zig_code(code)}\n```" for code in zig_codeblocks | ||
| f"```ansi\n{highlight_zig_code(code, theme)}\n```" | ||
| for code in zig_codeblocks | ||
| ) | ||
| for codeblock in zig_codeblocks: | ||
| original_source = f"```zig\n{codeblock}```" | ||
| highlighted_source = f"```ansi\n{highlight_zig_code(codeblock)}\n```" | ||
| highlighted_source = f"```ansi\n{highlight_zig_code(codeblock, theme)}\n```" | ||
| source = source.replace(original_source, highlighted_source) | ||
| return source |
@@ -1,2 +0,4 @@ | ||
| from dataclasses import KW_ONLY, dataclass | ||
| from __future__ import annotations | ||
| from dataclasses import KW_ONLY, dataclass, replace | ||
| from enum import Enum | ||
@@ -20,3 +22,7 @@ from itertools import compress | ||
| class Color(Enum): | ||
| # Names adjusted to match Discord's style | ||
| """ | ||
| An enumeration of 3-bit ANSI colors. | ||
| Some names were adjusted to match Discord's style. | ||
| """ | ||
| GRAY = "30" | ||
@@ -34,2 +40,8 @@ RED = "31" | ||
| class Style: | ||
| """ | ||
| A style for syntax highlighting. | ||
| Takes a `Color` and can optionally be bold and/or underlined. | ||
| Produces an SGR sequence when converted to a string. | ||
| """ | ||
| color: Color | ||
@@ -43,1 +55,20 @@ _: KW_ONLY | ||
| return _to_sgr(self.color.value, *modifiers) | ||
| @dataclass(slots=True, kw_only=True) | ||
| class Theme: | ||
| """A theme for syntax highlighting Zig code.""" | ||
| builtin_identifiers: Style | None = None | ||
| calls: Style | None = None | ||
| comments: Style | None = None | ||
| identifiers: Style | None = None | ||
| keywords: Style | None = None | ||
| numeric: Style | None = None | ||
| strings: Style | None = None | ||
| primitive_values: Style | None = None | ||
| types: Style | None = None | ||
| def copy(self) -> Theme: | ||
| """Create a copy of the `Theme`.""" | ||
| return replace(self) |
| import pytest | ||
| from zig_codeblocks.styling import Color, Reset, Style | ||
| from zig_codeblocks.styling import Color, Reset, Style, Theme | ||
@@ -32,1 +32,12 @@ | ||
| assert str(Reset[reset_type]) == expected_sgr | ||
| def test_theme_copy() -> None: | ||
| original = Theme(calls=Style(Color.BLUE)) | ||
| copy = original.copy() | ||
| assert original == copy | ||
| assert original is not copy | ||
| copy.calls = None | ||
| assert original != copy | ||
| assert original.calls is not None |
+1
-1
@@ -316,3 +316,3 @@ version = 1 | ||
| name = "zig-codeblocks" | ||
| version = "0.1.2" | ||
| version = "0.2.0" | ||
| source = { editable = "." } | ||
@@ -319,0 +319,0 @@ dependencies = [ |
Sorry, the diff of this file is not supported yet
Alert delta unavailable
Currently unable to show alert delta for PyPI packages.
27
3.85%391
28.2%587984
-0.25%