Skip to content

Commit

Permalink
add dark theme
Browse files Browse the repository at this point in the history
  • Loading branch information
alex-oleshkevich committed Oct 8, 2022
1 parent 1f50d1d commit 95606d7
Show file tree
Hide file tree
Showing 8 changed files with 161 additions and 41 deletions.
18 changes: 17 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,10 @@ poetry add starception
* request and app state
* platform information
* environment variables
* syntax highlighing
* syntax highlight
* open paths in editor (vscode only)
* exception chains
* dark theme

The middleware will automatically mask any value which key contains `key`, `secret`, `token`, `password`.

Expand Down Expand Up @@ -173,6 +174,21 @@ add_link_template('vscode', 'vscode://file/{path}:{lineno}')
set_editor('vscode')
```

## Dark theme

Switch between light/dark themes using `set_theme` utility.
> Currently, we use `pygments` for syntax highlighting, therefore theme must be set in the code.
> In future releases we may highlight code on client side, and then we can make Starception to follow your browser's
> theme.
```python
from starception import set_theme

set_theme('dark')
```

![image](dark.png)

## Credentials

* Look and feel inspired by [Phoenix Framework](https://www.phoenixframework.org/).
Binary file added dark.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 2 additions & 1 deletion examples/starlette.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from starlette.routing import Route
from starlette.templating import Jinja2Templates

from starception.exception_handler import install_error_handler
from starception import install_error_handler, set_theme

this_dir = os.path.dirname(__file__)
templates = Jinja2Templates(os.path.join(this_dir, 'templates'))
Expand Down Expand Up @@ -54,6 +54,7 @@ def css_view(request: Request) -> Response:
return templates.TemplateResponse('csstest.css', {'request': request})


set_theme('dark')
install_error_handler()
app = Starlette(
debug=True,
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[tool.poetry]
name = "starception"
description = "Beautiful debugging page for Starlette apps."
version = "0.5.0"
version = "0.5.1"
authors = ["Alex Oleshkevich <alex.oleshkevich@gmail.com>"]
license = "MIT"
readme = "README.md"
Expand Down
17 changes: 15 additions & 2 deletions starception/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,17 @@
from starception.exception_handler import add_link_template, exception_handler, install_error_handler, set_editor
from starception.exception_handler import (
add_link_template,
exception_handler,
install_error_handler,
set_editor,
set_theme,
)
from starception.middleware import StarceptionMiddleware

__all__ = ['StarceptionMiddleware', 'exception_handler', 'set_editor', 'add_link_template', 'install_error_handler']
__all__ = [
'StarceptionMiddleware',
'exception_handler',
'set_editor',
'add_link_template',
'install_error_handler',
'set_theme',
]
10 changes: 9 additions & 1 deletion starception/exception_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
from starlette.responses import HTMLResponse, PlainTextResponse, Response

_editor: str = 'none'
_theme: typing.Literal['light', 'dark'] = 'light'
open_link_templates: typing.Dict[str, str] = {
'none': 'file://{path}',
'vscode': 'vscode://file/{path}:{lineno}',
Expand All @@ -32,6 +33,11 @@ def set_editor(name: str) -> None:
_editor = name


def set_theme(theme: typing.Literal['light', 'dark']) -> None:
global _theme
_theme = theme


def add_link_template(editor: str, template: str) -> None:
"""
Add open file link template. The template accepts two format keys: path and
Expand Down Expand Up @@ -163,6 +169,7 @@ def highlight(value: str, filename: str) -> str:
from pygments.formatters import HtmlFormatter
from pygments.lexers import CssLexer, HtmlLexer, JavascriptLexer, PythonLexer

style = 'xcode' if _theme == 'light' else 'nord'
*_, extension = os.path.splitext(filename)
mapping = {
'.py': PythonLexer(),
Expand All @@ -172,7 +179,7 @@ def highlight(value: str, filename: str) -> str:
'.js': JavascriptLexer(),
}
if lexer := mapping.get(extension):
return highlight(value, lexer, HtmlFormatter(noclasses=True, nowrap=True, style='xcode')) # type: ignore
return highlight(value, lexer, HtmlFormatter(noclasses=True, nowrap=True, style=style)) # type: ignore
return value
except ImportError:
return value
Expand Down Expand Up @@ -240,6 +247,7 @@ def generate_html(request: Request, exc: Exception, limit: int = 15) -> str:
template = jinja.get_template('index.html')
return template.render(
{
'theme': _theme,
'exception_class': format_qual_name(traceback_obj.exc_type),
'error_message': str(exc) or '""',
'stack': stack,
Expand Down
64 changes: 33 additions & 31 deletions starception/templates/index.html
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{% import 'lib.html' as lib %}
<!DOCTYPE html>
<html lang="en">
<html lang="en" class="{{ theme }}">
<head>
<title>{{ exception_class }}: {{ error_message }} | Starception Debugger</title>
<meta name="viewport" content="width=device-width">
Expand All @@ -22,47 +22,49 @@
<main>
<!-- exception block -->
{% for stack_item in stack %}
{% if loop.index0 > 0 %}
<header class="section-header" data-toggle-trace="" data-trace-index="{{ loop.index0 }}">
Caused by
<div>
<div class="exception text-red">{{ stack_item.exc|e }}</div>
</div>
</header>
{% endif %}
<div data-trace-target="{{ loop.index0 }}" {% if loop.index0 > 0 %} class="collapsed"{% endif %}>
<div>
{% if loop.index0 > 0 %}
<div style="padding: 0 48px">
<header class="section-header" data-toggle-trace="" data-trace-index="{{ loop.index0 }}">
Caused by
<div>
<div class="exception text-red">{{ stack_item.exc|e }}</div>
</div>
</header>
{% endif %}
<div data-trace-target="{{ loop.index0 }}" {% if loop.index0 > 0 %} class="collapsed"{% endif %}>
{% if loop.index0 > 0 %}
{% if stack_item.solution %}
<div class="solution" style="margin-top: 8px">Hint: {{ stack_item.solution }}</div>
<div style="padding: 0 48px">
<div class="solution" style="margin-top: 8px">Hint: {{ stack_item.solution }}</div>
</div>
{% endif %}
</div>
{% endif %}
<section class="trace">
{% for frame in stack_item.frames|reverse %}
{% with frame=frame, is_current=loop.first %}
{% include 'code_snippet.html' %}
{% endwith %}
{% endfor %}

<div class="frames">
<div style="margin-bottom: 10px">
<label class="checkbox">
<input type="checkbox" id="vendor-frames" checked> Hide vendor frames
</label>
</div>
{% endif %}
<section class="trace">
{% for frame in stack_item.frames|reverse %}
{% with frame=frame, is_current=loop.first %}
{% include 'frame_line.html' %}
{% include 'code_snippet.html' %}
{% endwith %}
{% endfor %}
</div>
</section>

<div class="frames">
<div style="margin-bottom: 10px">
<label class="checkbox">
<input type="checkbox" id="vendor-frames" checked> Hide vendor frames
</label>
</div>
{% for frame in stack_item.frames|reverse %}
{% with frame=frame, is_current=loop.first %}
{% include 'frame_line.html' %}
{% endwith %}
{% endfor %}
</div>
</section>
</div>
</div>
{% endfor %}

<!-- request information -->
<section class="bg-white request-info">
<section class="bg-white">
{{ lib.details_row('Request', request_info, true) }}
{{ lib.details_row('Headers', request_headers) }}
{{ lib.details_row('Session', session) }}
Expand Down
Loading

0 comments on commit 95606d7

Please sign in to comment.