From 7fd5c307e006279c4dfe1143fc8630a99a91281c Mon Sep 17 00:00:00 2001 From: Barrett Ruth Date: Sat, 4 Oct 2025 23:20:54 -0400 Subject: [PATCH] feat: line nrs --- app.py | 82 ++++++++++++++++----------------------------- pyproject.toml | 1 - styles/common.css | 19 +++++++++-- styles/index.css | 1 + templates/gist.html | 44 +++++++++++++++++++++--- uv.lock | 13 +------ 6 files changed, 88 insertions(+), 72 deletions(-) diff --git a/app.py b/app.py index 2ceaef1..dcddfbd 100644 --- a/app.py +++ b/app.py @@ -5,21 +5,17 @@ import os from dataclasses import dataclass from pathlib import Path -from flask import Flask, jsonify, render_template, send_from_directory, abort, request -from pygments import highlight -from pygments.formatters import HtmlFormatter -from pygments.lexers import TextLexer, get_lexer_for_filename -from pygments.util import ClassNotFound +from flask import Flask, abort, jsonify, render_template, request, send_from_directory app = Flask(__name__, static_folder=None) -GIT_REPO_PATH = str(Path.home() / "dev") -GIST_PATH = str(Path.home() / "gists") -EXPORT_MARKER = "readme.md" +git_repo_path = str(Path.home() / "dev") +gist_path = str(Path.home() / "gists") +export_marker = "readme.md" if getpass.getuser() == "apache": - GIT_REPO_PATH = "/srv/git" - GIST_PATH = "/srv/gists" - EXPORT_MARKER = "git-daemon-export-ok" + git_repo_path = "/srv/git" + gist_path = "/srv/gists" + export_marker = "git-daemon-export-ok" @dataclass @@ -33,11 +29,11 @@ class Repository: def get_repositories(): repositories = [] - if not os.path.exists(GIT_REPO_PATH): + if not os.path.exists(git_repo_path): return repositories - for item in os.listdir(GIT_REPO_PATH): - repo_path = os.path.join(GIT_REPO_PATH, item) + for item in os.listdir(git_repo_path): + repo_path = os.path.join(git_repo_path, item) if not os.path.isdir(repo_path): continue @@ -48,7 +44,7 @@ def get_repositories(): ): continue - exported = os.path.exists(os.path.join(repo_path, EXPORT_MARKER)) + exported = os.path.exists(os.path.join(repo_path, export_marker)) description = "No description available" description_file = os.path.join(repo_path, "description") @@ -82,6 +78,24 @@ def get_repositories(): return repositories +@app.route("/gist/") +def serve_gist(filename): + base = Path(gist_path).resolve() + target = (base / filename).resolve() + if base not in target.parents and base != target: + abort(404) + if not target.exists() or not target.is_file(): + abort(404) + + try: + content = target.read_text(encoding="utf-8") + except UnicodeDecodeError: + return "Binary file cannot be displayed", 400 + + ext = target.suffix.lstrip(".") or "plaintext" + return render_template("gist.html", filename=filename, code=content, lang=ext) + + @app.route("/") def index(): repositories = [repo for repo in get_repositories() if repo.exported] @@ -98,43 +112,6 @@ def serve_scripts(filename): return send_from_directory("scripts", filename) -@app.route("/gist/") -def serve_gist(filename): - base = Path(GIST_PATH).resolve() - target = (base / filename).resolve() - if base not in target.parents and base != target: - abort(404) - - if not target.exists() or not target.is_file(): - abort(404) - - try: - content = target.read_text(encoding="utf-8") - except UnicodeDecodeError: - return "Binary file cannot be displayed", 400 - except OSError: - abort(404) - - try: - lexer = get_lexer_for_filename(target.name) - except ClassNotFound: - lexer = TextLexer() - - formatter = HtmlFormatter( - style="default", - cssclass="highlight", - linenos=False, - noclasses=True, - cssstyles="padding: 20px; font-size: 18px; background-color: #f8f8f8;", - ) - highlighted = highlight(content, lexer, formatter) - highlighted = highlighted.replace( - '', '' - ) - - return render_template("gist.html", filename=filename, highlighted_code=highlighted) - - @app.route("/") def serve_gist_root(filename): head = filename.split("/", 1)[0] @@ -166,4 +143,3 @@ def get_repo(repo_id): if __name__ == "__main__": app.run(host="0.0.0.0", port=5000, debug=True) - diff --git a/pyproject.toml b/pyproject.toml index c31394d..1fc734e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -7,5 +7,4 @@ requires-python = ">=3.11" dependencies = [ "flask>=3.1.1", "gunicorn>=23.0.0", - "pygments>=2.19.1", ] diff --git a/styles/common.css b/styles/common.css index 865d47e..5cd1ede 100644 --- a/styles/common.css +++ b/styles/common.css @@ -50,11 +50,10 @@ li { font-family: "Courier New", monospace; } -/* Code styling */ :not(pre) > code { font-family: "Courier New", Courier, monospace; margin: 0 5px; - font-size: 0.8em; /* Match the font size in barrettruth.com */ + font-size: 0.8em; white-space: nowrap; border: 1px solid #e1e1e1; background-color: #f4f4f4; @@ -64,3 +63,19 @@ li { max-width: 100%; user-select: all; } + +pre code { + font-family: "Snowflake", "Courier New", monospace; + font-size: 0.95rem; + line-height: 1.5; + background: transparent; + white-space: pre; + overflow-x: auto; +} + +.hljs-ln-numbers { + text-align: right; + color: #999; + border-right: 10px solid #ffffff; + user-select: none; +} diff --git a/styles/index.css b/styles/index.css index c9445c8..0743fd3 100644 --- a/styles/index.css +++ b/styles/index.css @@ -109,3 +109,4 @@ a { margin-top: 10px; font-size: 0.7em; } + diff --git a/templates/gist.html b/templates/gist.html index 06b02e6..9e65f22 100644 --- a/templates/gist.html +++ b/templates/gist.html @@ -7,17 +7,53 @@ + + + + {{ filename }} -
-

{{ filename }}

-
- {{ highlighted_code|safe }} + +
+

+ {{ filename }} +

+ +
+
{{ code | e }}
+ + + + + + + diff --git a/uv.lock b/uv.lock index 6195cbc..2ed07f6 100644 --- a/uv.lock +++ b/uv.lock @@ -1,5 +1,5 @@ version = 1 -revision = 2 +revision = 3 requires-python = ">=3.11" [[package]] @@ -56,14 +56,12 @@ source = { virtual = "." } dependencies = [ { name = "flask" }, { name = "gunicorn" }, - { name = "pygments" }, ] [package.metadata] requires-dist = [ { name = "flask", specifier = ">=3.1.1" }, { name = "gunicorn", specifier = ">=23.0.0" }, - { name = "pygments", specifier = ">=2.19.1" }, ] [[package]] @@ -156,15 +154,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/20/12/38679034af332785aac8774540895e234f4d07f7545804097de4b666afd8/packaging-25.0-py3-none-any.whl", hash = "sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484", size = 66469, upload-time = "2025-04-19T11:48:57.875Z" }, ] -[[package]] -name = "pygments" -version = "2.19.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/7c/2d/c3338d48ea6cc0feb8446d8e6937e1408088a72a39937982cc6111d17f84/pygments-2.19.1.tar.gz", hash = "sha256:61c16d2a8576dc0649d9f39e089b5f02bcd27fba10d8fb4dcc28173f7a45151f", size = 4968581, upload-time = "2025-01-06T17:26:30.443Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/8a/0b/9fcc47d19c48b59121088dd6da2488a49d5f72dacf8262e2790a1d2c7d15/pygments-2.19.1-py3-none-any.whl", hash = "sha256:9ea1544ad55cecf4b8242fab6dd35a93bbce657034b0611ee383099054ab6d8c", size = 1225293, upload-time = "2025-01-06T17:26:25.553Z" }, -] - [[package]] name = "werkzeug" version = "3.1.3"