by roundabout, Monday, 27 May 2024, 17:53:42 (1716832422), pushed by roundabout, Wednesday, 31 July 2024, 06:54:48 (1722408888)
Author identity: vlad <vlad.muntoiu@gmail.com>
a1601b17d6173c3f60152f074fe3b5f3da4199d4
app.py
@@ -415,7 +415,7 @@ def login():
category="info")
user_check = User.query.filter_by(username=username).first()
if user_check or email2: # make the honeypot look like a normal error
if user_check or email2: # make the honeypot look like a normal error
flask.flash(
Markup(
_(
doc/enduser/Formatting messages.md
@@ -39,7 +39,8 @@ Conversely, some extra features are available, primarily ones useful in
a code review environment. Some special cases are handled differently
compared to Gruber's markdown.
Very importantly, it is *******not******* CommonMark compliant!
Very importantly, it is *******not******* CommonMark compliant, like you see
in this sentence which had an underlined word.
There is also not a formalised specification for the syntax; first we need
to stabilise it.
@@ -293,7 +294,6 @@ inlines they will be in a paragraph anyways.
> It can contain multiple lines.
> ## And even other blocks.
> > And they can be nested.
> And you can be lazy.
>
> If this isn't what you want, it can have voids too.
~~~
@@ -304,7 +304,6 @@ turns into
> It can contain multiple lines.
> ## And even other blocks.
> > And they can be nested.
> And you can be lazy.
>
> If this isn't what you want, it can have voids too.
@@ -401,6 +400,9 @@ there's the first level of emphasis. You can see how they look below:
6. ******level 2+3******
7. *******level 1+2+3*******
The roundabout styles level 1 as italic, level 2 as bold, and level 3 as
underlined.
### Strikethrough
Strikethrough is represented by `~~` surrounding the text.
@@ -412,6 +414,10 @@ text and `--` for deleted text.
Links are represented by `[text](url)`. The text can contain inline elements.
Title attributes are currently not supported, but they will be.
#### Autolink
Autolinks are represented by `<url>`. With an autolink, the URL is the link
text as well.
#### Image
Images are represented by ``.
markdown.py
@@ -12,10 +12,14 @@ def only_chars(string, chars):
inline_regex = r"""
(?P<imageFlag>!?) \[ (?P<urlText>[^\[\]]*) \] \((?P<urlDestination>[^\(\)]*)\) # hyperlink or media
|
<(?P<urlDestination2>[^<>]*)> # autolink
|
(?P<em>\*{1,7}) (?P<textEm>(?:\\\*|[^*])*) (?P=em) # emphasis with * not requiring space on either side
|
(?:^|\s)(?P<em2>_{1,7}) (?P<textEm2>(?:\\.|[^*])*) (?P=em2)(?=\s|$) # emphasis with _ requiring space on at least one side
|
[``] (?P<textCode>(?:\\[``]|[^``])*) [``] # inline code (2 backticks)
|
[`] (?P<textCode>(?:\\[`]|[^`])*) [`] # inline code
|
(?P<strike>~{2}) (?P<textStrike>(?:\\[~]|[^~])*) (~{2}) # strikethrough
@@ -287,6 +291,17 @@ def parse_line(source):
tokens.append(Image(i.group("urlText"), i.group("urlDestination")))
else:
tokens.append(Link(i.group("urlText"), i.group("urlDestination")))
if i.group("urlDestination2"):
if "://" not in i.group("urlDestination2"):
url_text = i.group("urlDestination2").partition(":")[2] # remove tel, mailto, sms prefixes
url_destination = i.group("urlDestination2")
if url_destination.startswith("mailto:"):
url_destination = url_destination.replace("@", "@") # prevent email harvesting
url_text = url_text.replace("@", "@") # prevent protocol injection
else:
url_text = url_destination = i.group("urlDestination2")
tokens.append(Link(url_text, url_destination))
tokens.append(source[lookup:])
models.py
@@ -299,6 +299,7 @@ with (app.app_context()):
file = db.Column(db.String(256), nullable=True)
line_number = db.Column(db.Integer, nullable=True)
line_type = db.Column(db.SmallInteger, nullable=True, default=0, server_default="0") # 0 is deleted, 1 is modified
state = db.Column(db.SmallInteger, nullable=True, default=1)
review = db.Column(db.SmallInteger, nullable=True, default=0)
@@ -323,8 +324,10 @@ with (app.app_context()):
self.message = message
self.html = markdown.markdown2html(message).prettify()
self.file = file
self.line_number = line_number
self.pr_id = pr
self.line_number = int(line_number[1:])
self.line_type = int(line_number[0] == "+")
if pr:
self.pr = pr
repo.last_comment_id += 1
requirements.txt
@@ -45,4 +45,5 @@ flask_sqlalchemy
flask_bcrypt
flask_migrate
flask_httpauth
flask_babel
flask_babel
pygments
static/style.css
@@ -422,7 +422,7 @@ header {
overflow: auto;
}
.code-view :is(code, ins, del, x-codeline) {
.code-view > :is(code, ins, del, x-codeline) {
white-space: pre;
font: inherit;
color: inherit;
syntax_colouring.py
@@ -0,0 +1,76 @@
from pygments import highlight
from pygments.style import Style
from pygments import token
from pygments.lexers import PythonLexer
from pygments.formatters import HtmlFormatter
from bs4 import BeautifulSoup
class CustomStyle(Style):
default_style = ""
styles = {
token.Text: "",
token.Keyword: "bold #ff9800",
token.Name: "",
token.Operator: "",
token.Name.Class: "#ffeb3b",
token.Name.Function: "#be9ddb",
token.Name.Builtin: "#ab47bc",
token.Name.Attribute: "#4db6ac",
token.Name.Constant: "italic #ef5350",
token.Name.Decorator: "#bcaaa4",
token.Name.Function.Magic: "#e040fb",
token.Name.Label: "#ff4081",
token.String: "#8bc34a",
token.Number: "#42a5f5",
token.Punctuation: "#ff9800",
token.Comment: "italic #b0bec5",
token.Generic: "",
token.Escape: "#ff5722",
token.String.Escape: "#ff5722",
token.String.Regex: "#ffffff",
token.Comment.Preproc: "#536dfe",
token.Comment.Hashbang: "#536dfe",
token.Error: "#f44336",
token.Other: "",
token.Whitespace: "",
}
code = """
___all___ = ["hello_world"]
def interesting_function(func: Callable) -> Callable:
\"\"\"Print the function's result when called.
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam nec nulla
nec nulla laoreet fermentum. Integer id lacus ut odio interdum ultricies.
\"\"\"
def wrapper(*args, **kwargs):
result = func(*args, **kwargs) # avoid double evaluation
print(result)
return result
return wrapper
@interesting_function
def hello_world():
return "Hello, world!\\a" # a nice bell
if __name__ == "__main__":
hello_world()
"""
lexer = PythonLexer()
formatter = HtmlFormatter(style="colorful")
html_code = highlight(code, lexer, formatter)
soup = BeautifulSoup(html_code, "html.parser")
pre = soup.find("pre")
lines = pre.decode_contents().splitlines()
for line in lines:
line_soup = BeautifulSoup(line, "html.parser")
clean_line = line_soup.prettify()
print(clean_line)
templates/repository/repo-commit.html
@@ -33,7 +33,7 @@
<article class="card">
<section class="card-main">
<h2>{{ file }}</h2>
{% set vars = namespace(original_line=0, modified_line=0, hunk_started=false) %}
{% set vars = namespace(original_line=0, modified_line=0, hunk_started=false, actual_line=0, line_type=0) %}
{% for line in diff[file] %}
{% if line.startswith("@@") %}
{% if vars.hunk_started %}
@@ -47,28 +47,34 @@
<pre class="code-view">
{% elif vars.hunk_started %}
{% if line.startswith("+") %}
<button class="line-number" data-file="{{ file }}" data-line="{{ vars.modified_line }}">{{ vars.modified_line }} +</button>
<button class="line-number" data-file="{{ file }}" data-line="+{{ vars.modified_line }}">{{ vars.modified_line }} +</button>
<ins>{{ line[1:] }}</ins>
{% set vars.actual_line = vars.modified_line %}
{% set vars.line_type = 1 %}
{% set vars.modified_line = vars.modified_line + 1 %}
{% elif line.startswith("-") %}
<button class="line-number" data-file="{{ file }}" data-line="{{ vars.original_line }}">{{ vars.original_line }} -</button>
<button class="line-number" data-file="{{ file }}" data-line="-{{ vars.original_line }}">{{ vars.original_line }} -</button>
<del>{{ line[1:] }}</del>
{% set vars.actual_line = vars.original_line %}
{% set vars.line_type = 0 %}
{% set vars.original_line = vars.original_line + 1 %}
{% elif not line.startswith("\\") %}
{% if line %}
<button class="line-number" data-file="{{ file }}" data-line="{{ vars.modified_line }}">{{ vars.modified_line }} </button>
<button class="line-number" data-file="{{ file }}" data-line="+{{ vars.modified_line }}">{{ vars.modified_line }} </button>
<x-codeline>{{ line[1:] }}</x-codeline>
{% endif %}
{% if not line.startswith("@@") %}
{% set vars.actual_line = vars.modified_line %}
{% set vars.line_type = 1 %}
{% set vars.original_line = vars.original_line + 1 %}
{% set vars.modified_line = vars.modified_line + 1 %}
{% endif %}
{% endif %}
{% endif %}
{% for comment in comment_query.filter_by(commit=data, file=file, line_number=vars.original_line, state=1).all() %}
{% for comment in comment_query.filter_by(commit=data, file=file, line_number=vars.actual_line, line_type=vars.line_type, state=1).all() %}
<div class="comment">
<article>
{{ comment.text | safe }} {# this was generated by the markdown parser which escapes HML #}
{{ comment.text | safe }} {# this was generated by the markdown parser which escapes HTML #}
</article>
<small>
{% trans %}by{% endtrans %} <a href="/{{ comment.owner_name }}">{{ comment.owner.username }}</a>,
@@ -88,10 +94,10 @@
</x-buttonbox>
</div>
{% endfor %}
{% if comment_query.filter_by(commit=data, file=file, line_number=vars.original_line, state=0).count() %}
{% if comment_query.filter_by(commit=data, file=file, line_number=vars.actual_line, line_type=vars.line_type, state=0).count() %}
<details class="resolved-comments">
<summary>{% trans count=comment_query.filter_by(commit=data, file=file, line_number=vars.original_line, state=0).count() %}Resolved comments ({{ count }}){% endtrans %}</summary>
{% for comment in comment_query.filter_by(commit=data, file=file, line_number=vars.original_line, state=0).all() %}
<summary>{% trans count=comment_query.filter_by(commit=data, file=file, line_number=vars.actual_line, line_type=vars.line_type, state=0).count() %}Resolved comments ({{ count }}){% endtrans %}</summary>
{% for comment in comment_query.filter_by(commit=data, file=file, line_number=vars.actual_line, line_type=vars.line_type, state=0).all() %}
<div class="comment">
{{ comment.text | safe }} {# this was generated by the markdown parser which escapes HML #}
<x-buttonbox>
@@ -156,5 +162,6 @@
dialog.showModal();
});
});
document.querySelectorAll()
</script>
{% endblock %}