mirror of
https://github.com/ArthurSonzogni/FTXUI.git
synced 2025-09-28 16:29:34 +08:00
Compare commits
1 Commits
multiversi
...
main
Author | SHA1 | Date | |
---|---|---|---|
![]() |
a3103f5cd4 |
16
.github/workflows/documentation.yaml
vendored
16
.github/workflows/documentation.yaml
vendored
@@ -12,10 +12,6 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- name: "Checkout repository"
|
- name: "Checkout repository"
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v3
|
||||||
with:
|
|
||||||
fetch-depth: 0 # Need full history.
|
|
||||||
fetch-tags: true # Need tags.
|
|
||||||
|
|
||||||
|
|
||||||
- name: "Install cmake"
|
- name: "Install cmake"
|
||||||
uses: lukka/get-cmake@latest
|
uses: lukka/get-cmake@latest
|
||||||
@@ -34,23 +30,19 @@ jobs:
|
|||||||
sudo apt-get install graphviz;
|
sudo apt-get install graphviz;
|
||||||
|
|
||||||
- name: "Build documentation"
|
- name: "Build documentation"
|
||||||
run: |
|
|
||||||
python3 ./tools/build_multiversion_doc.py
|
|
||||||
|
|
||||||
- name: "Build examples"
|
|
||||||
run: >
|
run: >
|
||||||
mkdir -p multiversion_docs/main/examples;
|
|
||||||
mkdir build;
|
mkdir build;
|
||||||
cd build;
|
cd build;
|
||||||
emcmake cmake ..
|
emcmake cmake ..
|
||||||
-DCMAKE_BUILD_TYPE=Release
|
-DCMAKE_BUILD_TYPE=Release
|
||||||
-DFTXUI_BUILD_DOCS=OFF
|
-DFTXUI_BUILD_DOCS=ON
|
||||||
-DFTXUI_BUILD_EXAMPLES=ON
|
-DFTXUI_BUILD_EXAMPLES=ON
|
||||||
-DFTXUI_BUILD_TESTS=OFF
|
-DFTXUI_BUILD_TESTS=OFF
|
||||||
-DFTXUI_BUILD_TESTS_FUZZER=OFF
|
-DFTXUI_BUILD_TESTS_FUZZER=OFF
|
||||||
-DFTXUI_ENABLE_INSTALL=OFF
|
-DFTXUI_ENABLE_INSTALL=OFF
|
||||||
-DFTXUI_DEV_WARNINGS=OFF;
|
-DFTXUI_DEV_WARNINGS=OFF;
|
||||||
cmake --build . --target doc;
|
cmake --build . --target doc;
|
||||||
|
cmake --build . ;
|
||||||
rsync -amv
|
rsync -amv
|
||||||
--include='*/'
|
--include='*/'
|
||||||
--include='*.html'
|
--include='*.html'
|
||||||
@@ -60,13 +52,13 @@ jobs:
|
|||||||
--include='*.wasm'
|
--include='*.wasm'
|
||||||
--exclude='*'
|
--exclude='*'
|
||||||
examples
|
examples
|
||||||
../multiversion_docs/main/examples;
|
doc/doxygen/html;
|
||||||
|
|
||||||
- name: "Deploy"
|
- name: "Deploy"
|
||||||
uses: peaceiris/actions-gh-pages@v3
|
uses: peaceiris/actions-gh-pages@v3
|
||||||
with:
|
with:
|
||||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
publish_dir: multiversion_docs
|
publish_dir: build/doc/doxygen/html/
|
||||||
enable_jekyll: false
|
enable_jekyll: false
|
||||||
allow_empty_commit: false
|
allow_empty_commit: false
|
||||||
force_orphan: true
|
force_orphan: true
|
||||||
|
1
.gitignore
vendored
1
.gitignore
vendored
@@ -70,6 +70,5 @@ out/
|
|||||||
|
|
||||||
# tools directory:
|
# tools directory:
|
||||||
!tools/**/*.sh
|
!tools/**/*.sh
|
||||||
!tools/**/*.py
|
|
||||||
!tools/**/*.cpp
|
!tools/**/*.cpp
|
||||||
build/
|
build/
|
||||||
|
@@ -2,9 +2,16 @@
|
|||||||
<!-- start footer part -->
|
<!-- start footer part -->
|
||||||
<!--BEGIN GENERATE_TREEVIEW-->
|
<!--BEGIN GENERATE_TREEVIEW-->
|
||||||
<div id="nav-path" class="navpath"><!-- id is needed for treeview function! -->
|
<div id="nav-path" class="navpath"><!-- id is needed for treeview function! -->
|
||||||
|
<ul>
|
||||||
|
$navpath
|
||||||
|
<li class="footer">$generatedby <a href="https://www.doxygen.org/index.html"><img class="footer" src="$relpath^doxygen.svg" width="104" height="31" alt="doxygen"/></a> $doxygenversion </li>
|
||||||
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<!--END GENERATE_TREEVIEW-->
|
<!--END GENERATE_TREEVIEW-->
|
||||||
<!--BEGIN !GENERATE_TREEVIEW-->
|
<!--BEGIN !GENERATE_TREEVIEW-->
|
||||||
|
<hr class="footer"/><address class="footer"><small>
|
||||||
|
$generatedby <a href="https://www.doxygen.org/index.html"><img class="footer" src="$relpath^doxygen.svg" width="104" height="31" alt="doxygen"/></a> $doxygenversion
|
||||||
|
</small></address>
|
||||||
<!--END !GENERATE_TREEVIEW-->
|
<!--END !GENERATE_TREEVIEW-->
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
@@ -4,6 +4,7 @@
|
|||||||
#include <ftxui/component/component_options.hpp> // for ResizableSplitOption
|
#include <ftxui/component/component_options.hpp> // for ResizableSplitOption
|
||||||
#include <ftxui/dom/direction.hpp> // for Direction, Direction::Down, Direction::Left, Direction::Right, Direction::Up
|
#include <ftxui/dom/direction.hpp> // for Direction, Direction::Down, Direction::Left, Direction::Right, Direction::Up
|
||||||
#include <ftxui/util/ref.hpp> // for Ref
|
#include <ftxui/util/ref.hpp> // for Ref
|
||||||
|
#include <algorithm> // for max
|
||||||
#include <functional> // for function
|
#include <functional> // for function
|
||||||
#include <utility> // for move
|
#include <utility> // for move
|
||||||
|
|
||||||
|
@@ -1,222 +0,0 @@
|
|||||||
#!/usr/bin/env python3
|
|
||||||
|
|
||||||
import os
|
|
||||||
import subprocess
|
|
||||||
import shutil
|
|
||||||
import tempfile
|
|
||||||
import json
|
|
||||||
from pathlib import Path
|
|
||||||
from typing import List, Dict
|
|
||||||
|
|
||||||
class VersionInfo:
|
|
||||||
"""A structure to hold all information about a single documentation version."""
|
|
||||||
def __init__(self, name: str, is_main: bool, output_root: Path):
|
|
||||||
self.name = name
|
|
||||||
self.is_main = is_main
|
|
||||||
# Destination directory for the built docs, relative to the output root.
|
|
||||||
self.dest_dir = output_root if is_main else output_root / "en" / name
|
|
||||||
# The path to this version's index.html, relative to the output root.
|
|
||||||
self.index_path_from_root = self.dest_dir / "index.html"
|
|
||||||
|
|
||||||
def __repr__(self) -> str:
|
|
||||||
return f"VersionInfo(name='{self.name}', dest_dir='{self.dest_dir}')"
|
|
||||||
|
|
||||||
def run_command(command: List[str], check: bool = True, cwd: Path = None):
|
|
||||||
"""
|
|
||||||
Runs a command, prints its output, and handles errors.
|
|
||||||
"""
|
|
||||||
command_str = ' '.join(command)
|
|
||||||
print(f"Executing: {command_str} in {cwd or Path.cwd()}")
|
|
||||||
try:
|
|
||||||
# Using capture_output=True to get stdout/stderr
|
|
||||||
result = subprocess.run(
|
|
||||||
command,
|
|
||||||
capture_output=True,
|
|
||||||
text=True,
|
|
||||||
check=check,
|
|
||||||
cwd=cwd
|
|
||||||
)
|
|
||||||
if result.stdout:
|
|
||||||
print(result.stdout)
|
|
||||||
if result.stderr:
|
|
||||||
print(result.stderr)
|
|
||||||
return result
|
|
||||||
except subprocess.CalledProcessError as e:
|
|
||||||
print(f"ERROR: Command failed with exit code {e.returncode}")
|
|
||||||
print(f"Command: {command_str}")
|
|
||||||
if e.stdout:
|
|
||||||
print("--- STDOUT ---")
|
|
||||||
print(e.stdout)
|
|
||||||
if e.stderr:
|
|
||||||
print("--- STDERR ---")
|
|
||||||
print(e.stderr)
|
|
||||||
raise # Re-raise the exception to halt the script
|
|
||||||
|
|
||||||
def get_version_switcher_js(
|
|
||||||
current_version: VersionInfo,
|
|
||||||
all_versions: List[VersionInfo],
|
|
||||||
current_html_file: Path
|
|
||||||
) -> str:
|
|
||||||
"""
|
|
||||||
Generates the JavaScript for the version switcher dropdown.
|
|
||||||
|
|
||||||
This version pre-calculates the relative path from the current HTML file
|
|
||||||
to the index.html of every other version, simplifying the JS logic.
|
|
||||||
"""
|
|
||||||
version_names = [v.name for v in all_versions]
|
|
||||||
|
|
||||||
# Create a dictionary mapping version names to their relative URLs.
|
|
||||||
relative_paths: Dict[str, str] = {}
|
|
||||||
for version in all_versions:
|
|
||||||
# Calculate the relative path from the *parent directory* of the current HTML file
|
|
||||||
# to the target version's index.html.
|
|
||||||
path = os.path.relpath(version.index_path_from_root, current_html_file.parent)
|
|
||||||
relative_paths[version.name] = path
|
|
||||||
|
|
||||||
# Use json.dumps for safe serialization of data into JavaScript.
|
|
||||||
versions_json = json.dumps(version_names)
|
|
||||||
paths_json = json.dumps(relative_paths)
|
|
||||||
current_version_json = json.dumps(current_version.name)
|
|
||||||
|
|
||||||
return f"""
|
|
||||||
document.addEventListener('DOMContentLoaded', function() {{
|
|
||||||
const projectNumber = document.getElementById('projectnumber');
|
|
||||||
if (!projectNumber) {{
|
|
||||||
console.warn('Doxygen element with ID "projectnumber" not found. Cannot add version switcher.');
|
|
||||||
return;
|
|
||||||
}}
|
|
||||||
|
|
||||||
const versions = {versions_json};
|
|
||||||
const version_paths = {paths_json};
|
|
||||||
const currentVersion = {current_version_json};
|
|
||||||
|
|
||||||
// Sort versions: 'main' first, then others numerically descending.
|
|
||||||
versions.sort((a, b) => {{
|
|
||||||
if (a === 'main') return -1;
|
|
||||||
if (b === 'main') return 1;
|
|
||||||
return b.localeCompare(a, undefined, {{ numeric: true, sensitivity: 'base' }});
|
|
||||||
}});
|
|
||||||
|
|
||||||
const select = document.createElement('select');
|
|
||||||
select.onchange = function() {{
|
|
||||||
const selectedVersion = this.value;
|
|
||||||
// Navigate directly to the pre-calculated relative path.
|
|
||||||
if (selectedVersion !== currentVersion) {{
|
|
||||||
window.location.href = version_paths[selectedVersion];
|
|
||||||
}}
|
|
||||||
}};
|
|
||||||
|
|
||||||
versions.forEach(v => {{
|
|
||||||
const option = document.createElement('option');
|
|
||||||
option.value = v;
|
|
||||||
option.textContent = v;
|
|
||||||
if (v === currentVersion) {{
|
|
||||||
option.selected = true;
|
|
||||||
}}
|
|
||||||
select.appendChild(option);
|
|
||||||
}});
|
|
||||||
|
|
||||||
// Replace the Doxygen project number element with our dropdown.
|
|
||||||
projectNumber.replaceWith(select);
|
|
||||||
|
|
||||||
// Apply some styling to make it look good.
|
|
||||||
Object.assign(select.style, {{
|
|
||||||
backgroundColor: 'rgba(0, 0, 0, 0.8)',
|
|
||||||
color: 'white',
|
|
||||||
border: '1px solid rgba(255, 255, 255, 0.2)',
|
|
||||||
padding: '5px',
|
|
||||||
borderRadius: '5px',
|
|
||||||
fontSize: '14px',
|
|
||||||
fontFamily: 'inherit',
|
|
||||||
marginLeft: '10px',
|
|
||||||
cursor: 'pointer'
|
|
||||||
}});
|
|
||||||
}});
|
|
||||||
"""
|
|
||||||
|
|
||||||
def main():
|
|
||||||
"""Main function to build multi-version documentation."""
|
|
||||||
root_dir = Path.cwd()
|
|
||||||
output_dir = root_dir / "multiversion_docs"
|
|
||||||
|
|
||||||
print("--- 1. Cleaning up old documentation ---")
|
|
||||||
if output_dir.exists():
|
|
||||||
shutil.rmtree(output_dir)
|
|
||||||
output_dir.mkdir(parents=True, exist_ok=True)
|
|
||||||
|
|
||||||
print("--- 2. Getting versions from git ---")
|
|
||||||
git_tags_result = run_command(["git", "tag", "--list", "v*"])
|
|
||||||
# Create a list of version names, starting with 'main'.
|
|
||||||
version_names = ["main"] + sorted(
|
|
||||||
git_tags_result.stdout.splitlines(),
|
|
||||||
reverse=True
|
|
||||||
)
|
|
||||||
# For demonstration, limit the number of versions. Remove this in production.
|
|
||||||
version_names = version_names[:4]
|
|
||||||
print(f"Versions to build: {', '.join(version_names)}")
|
|
||||||
|
|
||||||
# Pre-compute all version information and paths.
|
|
||||||
versions = [
|
|
||||||
VersionInfo(name, name == "main", output_dir)
|
|
||||||
for name in version_names
|
|
||||||
]
|
|
||||||
|
|
||||||
with tempfile.TemporaryDirectory() as build_dir_str:
|
|
||||||
build_dir = Path(build_dir_str)
|
|
||||||
# --- 3. Build documentation for each version ---
|
|
||||||
for version in versions:
|
|
||||||
print(f"\n--- Building docs for version: {version.name} ---")
|
|
||||||
|
|
||||||
# Create a temporary directory for this version's source code.
|
|
||||||
version_src_dir = build_dir / f"src_{version.name}"
|
|
||||||
version_src_dir.mkdir()
|
|
||||||
|
|
||||||
# Check out the version's source code from git.
|
|
||||||
archive_path = version_src_dir / "source.tar"
|
|
||||||
run_command([
|
|
||||||
"git", "archive", version.name,
|
|
||||||
"--format=tar", f"--output={archive_path}"
|
|
||||||
])
|
|
||||||
run_command(["tar", "-xf", str(archive_path)], cwd=version_src_dir)
|
|
||||||
archive_path.unlink()
|
|
||||||
|
|
||||||
# Configure and build the docs using CMake.
|
|
||||||
version_build_dir = build_dir / f"build_{version.name}"
|
|
||||||
version_build_dir.mkdir()
|
|
||||||
run_command([
|
|
||||||
"cmake", str(version_src_dir), "-DFTXUI_BUILD_DOCS=ON"
|
|
||||||
], cwd=version_build_dir)
|
|
||||||
run_command(["make", "doc"], cwd=version_build_dir)
|
|
||||||
|
|
||||||
# Copy the generated HTML files to the final destination.
|
|
||||||
doxygen_html_dir = version_build_dir / "doc" / "doxygen" / "html"
|
|
||||||
if not doxygen_html_dir.is_dir():
|
|
||||||
print(f"FATAL: Doxygen HTML output not found for version {version.name}")
|
|
||||||
exit(1)
|
|
||||||
|
|
||||||
print(f"Copying files to: {version.dest_dir}")
|
|
||||||
shutil.copytree(doxygen_html_dir, version.dest_dir, dirs_exist_ok=True)
|
|
||||||
|
|
||||||
# --- 4. Inject version switcher into all HTML files ---
|
|
||||||
print("\n--- Injecting version switcher JavaScript ---")
|
|
||||||
for version in versions:
|
|
||||||
if not version.dest_dir.exists():
|
|
||||||
print(f"Warning: Destination directory for {version.name} does not exist. Skipping JS injection.")
|
|
||||||
continue
|
|
||||||
|
|
||||||
print(f"Processing HTML files in: {version.dest_dir}")
|
|
||||||
for html_file in version.dest_dir.rglob("*.html"):
|
|
||||||
js_script = get_version_switcher_js(version, versions, html_file)
|
|
||||||
script_tag = f'<script>{js_script}</script>'
|
|
||||||
|
|
||||||
content = html_file.read_text(encoding='utf-8')
|
|
||||||
# Inject the script right before the closing body tag.
|
|
||||||
new_content = content.replace("</body>", f"{script_tag}\n</body>")
|
|
||||||
html_file.write_text(new_content, encoding='utf-8')
|
|
||||||
|
|
||||||
print("\n--- 5. Finalizing ---")
|
|
||||||
print("Multi-version documentation generated successfully!")
|
|
||||||
print(f"Output located in: {output_dir.resolve()}")
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
main()
|
|
Reference in New Issue
Block a user