Skip to content

Commit c7af9c1

Browse files
Merge branch 'main' into VsCode-Extension
2 parents b56d328 + 09ffc44 commit c7af9c1

File tree

17 files changed

+511
-70
lines changed

17 files changed

+511
-70
lines changed

docs/frontpage.png

21.3 KB
Loading

src/gitingest/utils/query_parser_utils.py

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -60,22 +60,48 @@ def _is_valid_pattern(pattern: str) -> bool:
6060

6161
def _validate_host(host: str) -> None:
6262
"""
63-
Validate the given host against the known Git hosts.
63+
Validate a hostname.
64+
65+
The host is accepted if it is either present in the hard-coded `KNOWN_GIT_HOSTS` list or if it satisfies the
66+
simple heuristics in `_looks_like_git_host`, which try to recognise common self-hosted Git services (e.g. GitLab
67+
instances on sub-domains such as `gitlab.example.com` or `git.example.com`).
6468
6569
Parameters
6670
----------
6771
host : str
68-
The host to validate.
72+
Hostname (case-insensitive).
6973
7074
Raises
7175
------
7276
ValueError
73-
If the host is not a known Git host.
77+
If the host cannot be recognised as a probable Git hosting domain.
7478
"""
75-
if host not in KNOWN_GIT_HOSTS:
79+
host = host.lower()
80+
if host not in KNOWN_GIT_HOSTS and not _looks_like_git_host(host):
7681
raise ValueError(f"Unknown domain '{host}' in URL")
7782

7883

84+
def _looks_like_git_host(host: str) -> bool:
85+
"""
86+
Check if the given host looks like a Git host.
87+
88+
The current heuristic returns `True` when the host starts with `git.` (e.g. `git.example.com`) or starts with
89+
`gitlab.` (e.g. `gitlab.company.com`).
90+
91+
Parameters
92+
----------
93+
host : str
94+
Hostname (case-insensitive).
95+
96+
Returns
97+
-------
98+
bool
99+
True if the host looks like a Git host, otherwise False.
100+
"""
101+
host = host.lower()
102+
return host.startswith(("git.", "gitlab."))
103+
104+
79105
def _validate_url_scheme(scheme: str) -> None:
80106
"""
81107
Validate the given scheme against the known schemes.
@@ -90,6 +116,7 @@ def _validate_url_scheme(scheme: str) -> None:
90116
ValueError
91117
If the scheme is not 'http' or 'https'.
92118
"""
119+
scheme = scheme.lower()
93120
if scheme not in ("https", "http"):
94121
raise ValueError(f"Invalid URL scheme '{scheme}' in URL")
95122

src/server/main.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,19 @@ async def robots() -> FileResponse:
104104
return FileResponse("static/robots.txt")
105105

106106

107+
@app.get("/llm.txt")
108+
async def llm_txt() -> FileResponse:
109+
"""
110+
Serve the `llm.txt` file to provide information about the site to LLMs.
111+
112+
Returns
113+
-------
114+
FileResponse
115+
The `llm.txt` file located in the static directory.
116+
"""
117+
return FileResponse("static/llm.txt")
118+
119+
107120
# Include routers for modular endpoints
108121
app.include_router(index)
109122
app.include_router(download)

src/server/query_processor.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,9 @@ async def process_query(
9191
if not query.url:
9292
raise ValueError("The 'url' parameter is required.")
9393

94+
# Sets the "<user>/<repo>" for the page title
95+
context["short_repo_url"] = f"{query.user_name}/{query.repo_name}"
96+
9497
clone_config = query.extract_clone_config()
9598
await clone_repo(clone_config, token=token)
9699
summary, tree, content = ingest_query(query)

src/server/templates/base.jinja

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,13 @@
3333
<meta property="og:url" content="{{ request.url }}">
3434
<meta property="og:image" content="/static/og-image.png">
3535
<title>
36-
{% block title %}Gitingest{% endblock %}
36+
{% block title %}
37+
{% if short_repo_url %}
38+
Gitingest - {{ short_repo_url }}
39+
{% else %}
40+
Gitingest
41+
{% endif %}
42+
{% endblock %}
3743
</title>
3844
<script src="https://cdn.tailwindcss.com"></script>
3945
<script src="/static/js/utils.js"></script>
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
<span class="inline-block transform -rotate-6 -translate-y-1 mx-1 px-1 bg-[#FE4A60] border border-gray-900 text-white text-[10px] font-bold shadow-[2px_2px_0_0_rgba(0,0,0,1)]">NEW</span>

src/server/templates/components/footer.jinja

Lines changed: 16 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,26 @@
11
<footer class="w-full border-t-[3px] border-gray-900 mt-auto">
22
<div class="max-w-4xl mx-auto px-4 py-4">
3-
<div class="grid grid-cols-3 items-center text-gray-900 text-sm">
4-
<!-- Left column - GitHub links -->
3+
<div class="grid grid-cols-2 items-center text-gray-900 text-sm">
4+
<!-- Left column - Extension and PyPI links -->
55
<div class="flex items-center space-x-4">
6-
<a href="https://github.com/cyclotruc/gitingest"
6+
<a href="https://chromewebstore.google.com/detail/git-ingest-turn-any-git-r/adfjahbijlkjfoicpjkhjicpjpjfaood"
77
target="_blank"
88
rel="noopener noreferrer"
99
class="hover:underline flex items-center">
10-
<svg class="w-4 h-4 mr-1"
11-
xmlns="http://www.w3.org/2000/svg"
12-
viewBox="0 0 496 512">
13-
<path fill="currentColor" d="M165.9 397.4c0 2-2.3 3.6-5.2 3.6-3.3.3-5.6-1.3-5.6-3.6 0-2 2.3-3.6 5.2-3.6 3-.3 5.6 1.3 5.6 3.6zm-31.1-4.5c-.7 2 1.3 4.3 4.3 4.9 2.6 1 5.6 0 6.2-2s-1.3-4.3-4.3-5.2c-2.6-.7-5.5.3-6.2 2.3zm44.2-1.7c-2.9.7-4.9 2.6-4.6 4.9.3 2 2.9 3.3 5.9 2.6 2.9-.7 4.9-2.6 4.6-4.6-.3-1.9-3-3.2-5.9-2.9zM244.8 8C106.1 8 0 113.3 0 252c0 110.9 69.8 205.8 169.5 239.2 12.8 2.3 17.3-5.6 17.3-12.1 0-6.2-.3-40.4-.3-61.4 0 0-70 15-84.7-29.8 0 0-11.4-29.1-27.8-36.6 0 0-22.9-15.7 1.6-15.4 0 0 24.9 2 38.6 25.8 21.9 38.6 58.6 27.5 72.9 20.9 2.3-16 8.8-27.1 16-33.7-55.9-6.2-112.3-14.3-112.3-110.5 0-27.5 7.6-41.3 23.6-58.9-2.6-6.5-11.1-33.3 2.6-67.9 20.9-6.5 69 27 69 27 20-5.6 41.5-8.5 62.8-8.5s42.8 2.9 62.8 8.5c0 0 48.1-33.6 69-27 13.7 34.7 5.2 61.4 2.6 67.9 16 17.7 25.8 31.5 25.8 58.9 0 96.5-58.9 104.2-114.8 110.5 9.2 7.9 17 22.9 17 46.4 0 33.7-.3 75.4-.3 83.6 0 6.5 4.6 14.4 17.3 12.1C428.2 457.8 496 362.9 496 252 496 113.3 383.5 8 244.8 8zM97.2 352.9c-1.3 1-1 3.3.7 5.2 1.6 1.6 3.9 2.3 5.2 1 1.3-1 1-3.3-.7-5.2-1.6-1.6-3.9-2.3-5.2-1zm-10.8-8.1c-.7 1.3.3 2.9 2.3 3.9 1.6 1 3.6.7 4.3-.7.7-1.3-.3-2.9-2.3-3.9-2-.6-3.6-.3-4.3.7zm32.4 35.6c-1.6 1.3-1 4.3 1.3 6.2 2.3 2.3 5.2 2.6 6.5 1 1.3-1.3.7-4.3-1.3-6.2-2.2-2.3-5.2-2.6-6.5-1zm-11.4-14.7c-1.6 1-1.6 3.6 0 5.9 1.6 2.3 4.3 3.3 5.6 2.3 1.6-1.3 1.6-3.9 0-6.2-1.4-2.3-4-3.3-5.6-2z" />
14-
</svg>
15-
Suggest a feature
10+
<img src="https://img.icons8.com/ios/50/chrome--v1.png"
11+
alt="chrome"
12+
class="w-4 h-4 mr-1">
13+
Extension
14+
</a>
15+
<a href="https://pypi.org/project/gitingest/"
16+
target="_blank"
17+
rel="noopener noreferrer"
18+
class="hover:underline flex items-center">
19+
<img src="https://img.icons8.com/windows/32/python.png"
20+
alt="python"
21+
class="w-4 h-4 mr-1">
22+
Python package
1623
</a>
17-
</div>
18-
<!-- Middle column - Made with love -->
19-
<div class="flex flex-col justify-center items-center">
20-
<div class="flex items-center">
21-
made with ❤️ by
22-
<a href="https://x.com/romdot2"
23-
target="_blank"
24-
rel="noopener noreferrer"
25-
class="ml-1 hover:underline">@rom2</a>
26-
</div>
27-
<div class="flex items-center mt-1">
28-
Check out my
29-
<a href="https://pad.ws"
30-
target="_blank"
31-
rel="noopener noreferrer"
32-
referrerpolicy="origin"
33-
class="ml-1 hover:underline">latest project</a>
34-
</div>
3524
</div>
3625
<!-- Right column - Discord -->
3726
<div class="flex justify-end">

src/server/templates/components/git_form.jinja

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
const row = document.getElementById('controlsRow');
2525
const show = checkbox.checked;
2626
container.classList.toggle('hidden', !show);
27-
row.classList.toggle('mb-8', show);
27+
row.classList.toggle('mb-12', show);
2828
}
2929
</script>
3030
<div class="relative">
@@ -129,6 +129,7 @@
129129
onchange="toggleAccessSettings()"
130130
{% if token %}checked{% endif %}>
131131
<label for="showAccessSettings" class="text-gray-900">Private Repository</label>
132+
{% include "components/badge_new.jinja" %}
132133
</div>
133134
<!-- PAT field -->
134135
<div id="accessSettingsContainer"

src/server/templates/components/navbar.jinja

Lines changed: 4 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -34,24 +34,10 @@
3434
</div>
3535
<!-- Navigation with updated styling -->
3636
<nav class="flex items-center space-x-6">
37-
<!-- Simplified Chrome extension button -->
38-
<a href="https://chromewebstore.google.com/detail/git-ingest-turn-any-git-r/adfjahbijlkjfoicpjkhjicpjpjfaood"
39-
target="_blank"
40-
rel="noopener noreferrer"
41-
class="text-gray-900 hover:-translate-y-0.5 transition-transform flex items-center gap-1.5">
42-
<div class="flex items-center">
43-
<svg xmlns="http://www.w3.org/2000/svg"
44-
width="24"
45-
height="24"
46-
viewBox="0 0 50 50"
47-
fill="none"
48-
stroke="currentColor"
49-
stroke-width="3"
50-
class="w-4 h-4 mx-1">
51-
<path d="M 25 2 C 12.309295 2 2 12.309295 2 25 C 2 37.690705 12.309295 48 25 48 C 37.690705 48 48 37.690705 48 25 C 48 12.309295 37.690705 2 25 2 z M 25 4 C 32.987976 4 39.925645 8.44503 43.476562 15 L 25 15 A 1.0001 1.0001 0 0 0 24.886719 15.005859 C 19.738868 15.064094 15.511666 19.035373 15.046875 24.078125 L 8.0351562 12.650391 C 11.851593 7.4136918 18.014806 4 25 4 z M 6.8242188 14.501953 L 16.476562 30.230469 A 1.0001 1.0001 0 0 0 16.591797 30.388672 A 1.0001 1.0001 0 0 0 16.59375 30.392578 C 18.3752 33.158533 21.474925 35 25 35 C 26.413063 35 27.756327 34.701734 28.976562 34.169922 L 22.320312 45.824219 C 11.979967 44.509804 4 35.701108 4 25 C 4 21.169738 5.0375742 17.591533 6.8242188 14.501953 z M 25 17 C 29.430123 17 33 20.569877 33 25 C 33 26.42117 32.629678 27.751591 31.984375 28.90625 A 1.0001 1.0001 0 0 0 31.982422 28.908203 A 1.0001 1.0001 0 0 0 31.947266 28.966797 C 30.57172 31.37734 27.983486 33 25 33 C 20.569877 33 17 29.430123 17 25 C 17 20.569877 20.569877 17 25 17 z M 30.972656 17 L 44.421875 17 C 45.43679 19.465341 46 22.165771 46 25 C 46 36.609824 36.609824 46 25 46 C 24.842174 46 24.686285 45.991734 24.529297 45.988281 L 33.683594 29.958984 A 1.0001 1.0001 0 0 0 33.742188 29.841797 C 34.541266 28.405674 35 26.755664 35 25 C 35 21.728612 33.411062 18.825934 30.972656 17 z" />
52-
</svg>
53-
Extension
54-
</div>
37+
<a href="/llm.txt"
38+
class="text-gray-900 hover:-translate-y-0.5 transition-transform flex items-center">
39+
{% include "components/badge_new.jinja" %}
40+
/llm.txt
5541
</a>
5642
<!-- Simplified VS Code extension button -->
5743
<a href="https://marketplace.visualstudio.com/items?itemName=iamshreydxv.gitingest"

src/server/templates/components/result.jinja

Lines changed: 32 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,48 @@
11
<script>
2-
function getFileName(line) {
3-
// Skips "|", "└", "├" found in file tree
4-
const index = line.search(/[a-zA-Z0-9]/);
5-
return line.substring(index).trim();
2+
function getFileName(element) {
3+
const indentSize = 4;
4+
let path = "";
5+
let prevIndentLevel = null;
6+
7+
while (element) {
8+
const line = element.textContent;
9+
const index = line.search(/[a-zA-Z0-9_.-]/);
10+
const indentLevel = index / indentSize;
11+
12+
// Stop when we reach or go above the top-level directory
13+
if (indentLevel <= 1) {
14+
break;
15+
}
16+
17+
// Only include directories that are one level above the previous
18+
if (prevIndentLevel === null || indentLevel === prevIndentLevel - 1) {
19+
const fileName = line.substring(index).trim();
20+
path = fileName + path;
21+
prevIndentLevel = indentLevel;
22+
}
23+
24+
element = element.previousElementSibling;
25+
}
26+
27+
return path;
628
}
729
830
function toggleFile(element) {
931
const patternInput = document.getElementById("pattern");
1032
const patternFiles = patternInput.value ? patternInput.value.split(",").map(item => item.trim()) : [];
1133
12-
if (element.textContent.includes("Directory structure:")) {
34+
const directoryContainer = document.getElementById("directory-structure-container");
35+
const treeLineElements = Array.from(directoryContainer.children).filter(child => child.tagName === "PRE");
36+
37+
// Skip the first two tree lines (header and repository name)
38+
if (treeLineElements[0] === element || treeLineElements[1] === element) {
1339
return;
1440
}
1541
1642
element.classList.toggle('line-through');
1743
element.classList.toggle('text-gray-500');
1844
19-
const fileName = getFileName(element.textContent);
45+
const fileName = getFileName(element);
2046
const fileIndex = patternFiles.indexOf(fileName);
2147
2248
if (fileIndex !== -1) {

0 commit comments

Comments
 (0)