diff --git a/.github/workflows/docs.yml b/.github/workflows/website.yml similarity index 55% rename from .github/workflows/docs.yml rename to .github/workflows/website.yml index d717c75f8..4174b0c10 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/website.yml @@ -16,21 +16,28 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout uutils.github.io Repository - uses: actions/checkout@v4 + uses: actions/checkout@v5 with: repository: uutils/uutils.github.io path: './uutils.github.io' fetch-depth: 0 - name: Checkout Coreutils Repository - uses: actions/checkout@v4 + uses: actions/checkout@v5 with: repository: uutils/coreutils path: './coreutils' fetch-depth: 0 + - name: Checkout Coreutils L10n Repository + uses: actions/checkout@v5 + with: + repository: uutils/coreutils-l10n + path: './coreutils-l10n' + fetch-depth: 0 + - name: Checkout Findutils Repository - uses: actions/checkout@v4 + uses: actions/checkout@v5 with: repository: uutils/findutils path: './findutils' @@ -39,34 +46,73 @@ jobs: - name: Install `rust` toolchain uses: dtolnay/rust-toolchain@stable - - name: Install `libacl` + - name: Install system deps run: | - sudo apt install libacl1-dev - - - name: Download tldr archive - run: | - curl https://tldr.sh/assets/tldr.zip --output coreutils/docs/tldr.zip + sudo apt install libacl1-dev libselinux1-dev libsystemd-dev + pip install babel - name: Install necessary tools (mdbook and mdbook-toc) uses: taiki-e/install-action@v2 with: tool: mdbook,mdbook-toc + - name: Copy l10n locales into coreutils + run: | + # Only copy locales into utilities that already exist in coreutils + # Exclude en-US.ftl to preserve the coreutils English originals + for util_dir in coreutils-l10n/src/uu/*/; do + util=$(basename "$util_dir") + if [ -d "coreutils/src/uu/$util/locales" ]; then + for ftl in "$util_dir"/locales/*.ftl; do + [ -f "$ftl" ] || continue + [ "$(basename "$ftl")" = "en-US.ftl" ] && continue + cp "$ftl" "coreutils/src/uu/$util/locales/" + done + fi + done + # Copy uucore l10n files, excluding en-US.ftl + if [ -d "coreutils-l10n/src/uucore/locales" ]; then + for ftl in coreutils-l10n/src/uucore/locales/*.ftl; do + [ -f "$ftl" ] || continue + [ "$(basename "$ftl")" = "en-US.ftl" ] && continue + cp "$ftl" "coreutils/src/uucore/locales/" + done + fi + + - name: Patch mdbook theme with language selector + run: | + uutils.github.io/scripts/patch-mdbook-theme.sh coreutils/docs coreutils-l10n + - name: Build Coreutils Docs run: | cd coreutils + # Download and repack tldr zip: uudoc expects pages/common/ prefix + curl -sfL https://github.com/tldr-pages/tldr/releases/download/v2.3/tldr-pages.zip -o /tmp/tldr-raw.zip || true + if [ -f /tmp/tldr-raw.zip ]; then + mkdir -p /tmp/tldr-repack/pages + cd /tmp/tldr-repack && unzip -o /tmp/tldr-raw.zip -d pages/ > /dev/null + zip -r "$OLDPWD/docs/tldr.zip" pages/ > /dev/null + cd "$OLDPWD" + fi cargo run --bin uudoc --all-features cd docs + # Remove deprecated 'multilingual' field unsupported by newer mdbook + sed -i '/^multilingual/d' book.toml mdbook build + - name: Build Coreutils Docs (translations) + run: | + uutils.github.io/scripts/build-docs-l10n.sh coreutils + - name: Build Findutils Docs run: | - cd findutils - cd docs + cd findutils/docs + # Remove deprecated 'multilingual' field unsupported by newer mdbook + sed -i '/^multilingual/d' book.toml mdbook build - + - name: Run Zola - uses: shalzz/zola-deploy-action@v0.18.0 + uses: shalzz/zola-deploy-action@v0.21.0 env: BUILD_DIR: uutils.github.io BUILD_ONLY: true @@ -76,6 +122,12 @@ jobs: cp -r uutils.github.io/public public cp -r coreutils/docs/book public/coreutils/docs cp -r findutils/docs/book public/findutils/docs + # Copy translated docs to /coreutils/docs-{lang}/ + for lang_dir in coreutils/docs/book-*/; do + [ -d "$lang_dir" ] || continue + lang=$(basename "$lang_dir" | sed 's/^book-//') + cp -r "$lang_dir" "public/coreutils/docs-${lang}" + done - name: Upload artifact for checking the output uses: actions/upload-artifact@v4 @@ -83,7 +135,7 @@ jobs: path: ./public - name: Upload artifact for pages - uses: actions/upload-pages-artifact@v3 + uses: actions/upload-pages-artifact@v4 with: path: ./public @@ -158,6 +210,7 @@ jobs: url: ${{ steps.deployment.outputs.page_url }} runs-on: ubuntu-latest needs: build + if: (github.event_name == 'push' && github.ref == 'refs/heads/main') || github.event_name == 'schedule' steps: - name: Deploy to GitHub Pages id: deployment diff --git a/.gitignore b/.gitignore index 15ce475e7..d90d7f863 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ -/public/ \ No newline at end of file +/public/ +/static/syntax-* diff --git a/README.md b/README.md index 2baf0d1c4..f67b8508e 100644 --- a/README.md +++ b/README.md @@ -5,10 +5,10 @@ This repository generates the user and dev documentations of https://github.com/ ## User documentation It is available on: -https://uutils.github.io/user/ +https://uutils.github.io/coreutils/docs/ Can be generated with: -``` +```bash cargo run --bin uudoc --all-features cd docs mdbook build @@ -20,7 +20,7 @@ It is available on: https://uutils.github.io/dev/coreutils/ Can be generated with: -``` +```bash cargo doc --no-deps --all-features --workspace ``` diff --git a/config.toml b/config.toml index be03294fa..35730ecbb 100644 --- a/config.toml +++ b/config.toml @@ -7,10 +7,13 @@ description = "" default_language = "en" -paginate_by = 10 - -generate_feed = true +generate_feeds = true [markdown] highlight_code = true -highlight_theme = "OneHalfLight" +highlight_theme = "css" + +highlight_themes_css = [ + { theme = "OneHalfDark", filename = "syntax-theme-dark.css" }, + { theme = "OneHalfLight", filename = "syntax-theme-light.css" }, +] diff --git a/content/_index.md b/content/_index.md index f25cb1b4b..d5781f237 100644 --- a/content/_index.md +++ b/content/_index.md @@ -4,21 +4,26 @@ template = "index.html" +++
- -
uutils
+ + + + +
uutils
The uutils project reimplements ubiquitous command line utilities in Rust. Our goal is to modernize the utils, while retaining full compatibility with the existing utilities. +We are planning to replace all essential Linux tools. + # Projects

coreutils

- The commands you use everyday: ls, cp, etc. + The commands you use everyday: ls, cp, etc. Production ready!

diff --git a/content/blog/2024-02-extending.md b/content/blog/2024-02-extending.md deleted file mode 100644 index 74b05dab8..000000000 --- a/content/blog/2024-02-extending.md +++ /dev/null @@ -1,75 +0,0 @@ -+++ -title = "Extending the Coreutils project - Rewriting base tools in Rust " -draft = true -date = 2024-03-26 -authors = ["Sylvestre Ledru", "Terts Diepraam"] -+++ - -Over the last 4 years, we have been working at reimplementing some of the key Linux tools in Rust. We started with the [Coreutils](https://github.com/uutils/coreutils) and [findutils](https://github.com/uutils/findutils). - -As we approach feature parity with the GNU Coreutils implementation, and as its adoption in production environments continues to expand, we have been thinking about what is next. - -Given the overwhelming positive feedback around this initiative, we are going to extend our efforts to rewrite other parts of the modern Linux/Unix/Mac stack in Rust (still with Windows support in mind when relevant). -We also noticed a lot of contributions on these projects coming from a lot of different hackers (475 different contributors on Coreutils!). -With the growing enthusiasm for Rust and the eagerness to learn it, now is the best time to push this project. We think that rewriting in Rust will help with the longer term maintenance of the ecosystem, ensuring it stays robust, safe and welcoming for new generations of contributors. - -For the next projects, we are using the same approach: dropped-in replacement of the GNU C implementation. -For now, we are going to focus on: -* [diffutils](https://github.com/uutils/diffutils) (transferred by Michael Howell) - [Good first issues](https://github.com/uutils/diffutils/labels/good%20first%20issue) - Almost ready -* [procps](https://github.com/uutils/procps) - [Good first issues](https://github.com/uutils/procps/labels/good%20first%20issue) - 5 programs started -* [acl](https://github.com/uutils/acl) - [Good first issues](https://github.com/uutils/acl/labels/good%20first%20issue) - The 3 started -* [util-linux](https://github.com/uutils/util-linux) - [Good first issues](https://github.com/uutils/util-linux/labels/good%20first%20issue) - A couple programs started -* [bsdutils](https://github.com/uutils/bsdutils) - [Good first issues](https://github.com/uutils/bsdutils/labels/good%20first%20issue) - One program started -* [login](https://github.com/uutils/login/) - [Good first issues](https://github.com/uutils/login/labels/good%20first%20issue) - Just the skeleton -* [hostname](https://github.com/uutils/hostname/) - [Good first issues](https://github.com/uutils/hostname/labels/good%20first%20issue) - Almost empty - - -These packages are part of the essential list on Debian & Ubuntu. - - -Sylvestre Ledru, Terts Diepraam and Daniel Hofstetter - -FAQ -### - -How long is it going to take? ------------------------------ - -Some programs like diff, acl or hostname should be completed quickly. -Others will take years to be completed. - -Do you hate the GNU project? ----------------------------- - -Not at all: we often contribute to the upstream implementations when we identify issues, add missing tests, etc. - - -Why the MIT License? --------------------- - -For consistency purposes and not interested by a license debate, we are going to use the MIT license just like the Coreutils. - - -The binaries are too big? -------------------------- - -Does it really matter? Yes, Rust binaries are usually bigger than GNU but we don't think it is a blocker, even for embedded devices. - - -Is it really safer? -------------------- - -While Rust is clearly a better language than C/C++ for security, these programs are often very safe. It isn't a key argument for us for -this rewrite. - -What about performances? ------------------------- - -Although we haven't entered the optimization phase, Rust's modern design inherently facilitates some straightforward performance improvements. diff --git a/content/blog/2025-02-extending.md b/content/blog/2025-02-extending.md new file mode 100644 index 000000000..b1a66784a --- /dev/null +++ b/content/blog/2025-02-extending.md @@ -0,0 +1,90 @@ ++++ +title = "Extending the Coreutils project - Rewriting base tools in Rust" +date = 2025-02-01 +page_template = "post.html" +authors = ["Sylvestre Ledru"] ++++ + +As I [just presented at FOSDEM](https://sylvestre.ledru.info/coreutils-fosdem-2025/), we are moving into the next phase of the uutils project. + +Over the last five years, we have been working on reimplementing some of the key Linux tools in Rust. We started with the [Coreutils](https://github.com/uutils/coreutils) and [findutils](https://github.com/uutils/findutils). + +As we approach feature parity with the GNU Coreutils implementation, and as its adoption in production environments continues to expand, we have been thinking about what is next. + +Given the very positive feedback around this initiative, we are going to extend our efforts to rewrite other parts of the modern Linux/Unix/Mac stack in Rust (still with Windows support in mind when relevant). These efforts will be managed under the [uutils umbrella](https://github.com/uutils/), which will allow us to maintain a cohesive and unified approach across various utilities. + +We also noticed a lot of contributions on these projects coming from a diverse group of hackers (530 different contributors on Coreutils alone!). With the growing enthusiasm for Rust and the eagerness to learn it, now is the best time to push this project forward. Rewriting in Rust will help with the long-term maintenance of the ecosystem, ensuring it stays robust, safe, and welcoming for new generations of contributors. + +### Vision for the Future + +As we expand the scope of the project, we are working on a future where Rust becomes the backbone of essential Linux, Unix, and potentially macOS system tools. Our focus will be on improving security, ensuring long-term maintainability, and optimizing performance for both modern and legacy systems. Through the uutils umbrella, we aim to create a more secure, efficient, and scalable alternative to the traditional tools, replacing software developed in older, less secure programming languages like C. + +This project is also an investment for the future. C is becoming less popular with the next generation of developers. Just like how the Linux kernel continues to evolve and includes Rust, it is our responsibility to upgrade the core utilities of the system to a modern, safer programming language. By doing so, we ensure that the essential tools used in Linux/Unix systems remain relevant, maintainable, and accessible to future contributors. + +### Specific Benefits of Rust + +Rust offers several advantages over C/C++, particularly in terms of memory safety, concurrency, and performance. By eliminating common security issues such as null pointer dereferences and buffer overflows, Rust allows us to build tools that are inherently safer. Its modern compiler tooling also enables us to optimize performance without sacrificing code safety, ensuring that our utilities can handle the demands of modern computing environments while remaining easy to maintain. + +### Challenges and Opportunities + +As with any large-scale reimplementation, there are challenges to overcome. Porting complex utilities from C to Rust requires careful consideration of edge cases and platform-specific behaviors. Additionally, ensuring full compatibility across Linux, Unix, and macOS environments presents unique challenges. However, these challenges also offer opportunities for growth and innovation, allowing us to extend and refine core system utilities for modern needs. Rust's modern design gives us the chance to improve both security and performance while maintaining cross-platform compatibility. + +### Next Steps + +For the next phase of the project, we are adopting the same approach: a drop-in replacement of the C implementations. Here's what's coming next: + +| Name | Description | Status | +|----------------------------------------------------|----------------------------------------------------|-----------------------------| +| [acl](https://github.com/uutils/acl) | Access control list utilities | | +| [bsdutils](https://github.com/uutils/bsdutils) | Basic utilities for BSD compatibility | | +| [coreutils](https://github.com/uutils/coreutils) | Basic utilities for the system | Production level | +| [diffutils](https://github.com/uutils/diffutils) | File comparison utilities | Almost ready | +| [findutils](https://github.com/uutils/findutils) | Utilities for finding files | Getting close to completion | +| [hostname](https://github.com/uutils/hostname) | Utility to show or set system hostname | | +| [login](https://github.com/uutils/login) | User login management utilities | | +| [procps](https://github.com/uutils/procps) | Utilities for monitoring and controlling processes | | +| [util-linux](https://github.com/uutils/util-linux) | Utilities essential for Linux systems | | + +These packages are part of the essential list for Debian and Ubuntu, and we're excited to push their Rust reimplementation further. + +### GSoC 2024 Participation + +In 2024, we had the pleasure of mentoring three students during Google Summer of Code (GSoC): + +1. **Sreehari Prasad** worked on improving the support of Rust CCoreutils. His focus was on making uutils compatible with the GNU coreutils test suite. Sreehari resolved most of the failing tests for the `cp`, `mv`, and `ls` utilities and significantly enhanced compatibility. + +2. **Hanbings** tackled the implementation of key GNU `findutils` utilities like `xargs` and `find` in Rust. His work focused on improving compatibility with the GNU suite while enhancing performance, resulting in major progress on missing features and test code. + +3. **Krysztal Huang** worked on implementing the `procps` suite, which includes utilities like `slabtop`, `top`, `pgrep`, `pidof`, `ps`, `pidwait`, and `snice`. This project involved implementing some of these commands. + +### Call to Action for Contributors + +Contributors who are passionate about system-level programming and Rust are always welcome. Whether you're experienced with GNU utilities or just learning Rust, your contributions will be invaluable to this +project. You can get involved by picking up good-first issues, reviewing code, or even helping us test new features across various platforms. The [uutils GitHub organization](https://github.com/uutils) has all the information you need to get started. +You can also sponsor the project through [GitHub Sponsors](https://github.com/sponsors/uutils). + +### FAQ + +**How long is it going to take?** + +Some programs, like `diff`, `acl`, or `hostname`, could be completed quickly, while others will take years to finish. + +**Do you hate the GNU project?** + +Not at all. We often contribute to the upstream implementations when we identify issues, add missing tests, and so on. + +**Why the MIT License?** + +For consistency purposes. We're not interested in a license debate and will continue to use the MIT license, as we did with Coreutils. + +**The binaries are too big. Does it really matter?** + +Yes, Rust binaries are generally bigger than GNU's, but we don't think it's a blocker, even for embedded devices. + +**Is it really safer?** + +While Rust is better than C/C++ for security, these programs are often already very safe. Security is not the key argument for us in this rewrite even if Rust provides some automatic improvements. + +**What about performance?** + +Although we haven't started optimizing yet, Rust's design facilitates performance improvements naturally. We are confident that, in time, these tools will match or exceed the performance of their GNU counterparts. diff --git a/content/blog/_index.md b/content/blog/_index.md index f784a32f4..e16b5390b 100644 --- a/content/blog/_index.md +++ b/content/blog/_index.md @@ -5,4 +5,4 @@ page_template = "post.html" title = "Blog" +++ -You can subscribe to this blog with this [atom feed](/atom.xml). \ No newline at end of file +You can subscribe to this blog with this [atom feed](/atom.xml). diff --git a/content/gsoc.md b/content/gsoc.md index de386e3d5..07fd95dda 100644 --- a/content/gsoc.md +++ b/content/gsoc.md @@ -31,7 +31,7 @@ with uutils. coreutils and the other tools. 1. **Reach out to us!** We are happy to discuss potential projects and help you find a meaningful project for uutils. Tell us what interests you about the project and what experience you have and we can find a suitable project together. You can talk to the uutils maintainers on the [Discord server](https://discord.gg/wQVJbvJ). In particular, you can contact: * Sylvestre Ledru (@sylvestre on GitHub and Discord) - * Terts Diepraam (@tertsdiepraam on GitHub and @terts on Discord) + 2. **Get comfortable with uutils.** To find a good project you need to understand the codebase. We recommend that you take a look at the code, the issue tracker and maybe try to tackle some [good-first-issues](https://github.com/uutils/coreutils/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22). Also take a look at our [contributor guidelines](https://github.com/uutils/coreutils/blob/main/CONTRIBUTING.md). 3. **Find a project and a mentor.** We have a [list of potential projects](https://github.com/uutils/coreutils/wiki/GSOC-Project-Ideas) you can adapt or use as inspiration. Make sure discuss your ideas with the maintainers! Some project ideas below have suggested mentors you could contact. 4. **Write the application.** You can do this with your mentor. The application has to go through Google, so make sure to follow all the advice in Google's [Contributor Guide](https://google.github.io/gsocguides/student/writing-a-proposal). Please make sure you include your prior contributions to uutils in your application. @@ -58,88 +58,272 @@ Summarizing that page, each project should include: - Size (either ~175 or ~350 hours) - Difficulty (easy, medium or hard) -## Complete the `ls` GNU compatibility +## Performance optimization for coreutils -Most of the features in `ls` have been implemented by now. -However, a bunch of work remains on the color side for a full GNU compat. Other tests are failing. -We have 12 remaining failing tests. +While [uutils/coreutils](https://github.com/uutils/coreutils) has achieved strong GNU compatibility, some utilities can still benefit from performance improvements to match or exceed GNU coreutils speed. This project focuses on identifying performance bottlenecks and implementing optimizations across key utilities. -To get the list of failing tests, run: -``` -$ ./util/remaining-gnu-error.py |grep "/ls/" -``` +The goal is to systematically profile, benchmark, and optimize coreutils to ensure they are production-ready for performance-critical environments. -- Difficulty: Medium -- Size: 175 -- Mentors: Sylvestre -- Required skills: +Key areas of work include: +* Profiling utilities to identify performance bottlenecks (using perf, flamegraph, criterion) +* Creating comprehensive benchmark suite comparing against GNU coreutils +* Optimizing hot paths in frequently-used utilities (cat, cut, sort, uniq, wc, etc.) +* Implementing algorithmic improvements and efficient data structures +* Reducing allocations and improving memory usage patterns +* Leveraging SIMD instructions where applicable for data processing +* Optimizing I/O operations with proper buffering strategies +* Benchmarking across different file sizes and input patterns +* Setting up continuous performance monitoring in CI +* Documenting performance characteristics and optimization techniques + +- **Difficulty**: Medium +- **Size**: ~175 hours +- **Mentors**: TBD +- **Required skills**: - Rust - - Basic knowledge about the terminal + - Performance profiling and optimization techniques + - Understanding of systems programming and I/O optimization + - Benchmarking methodologies + - Knowledge of SIMD and parallel processing is a plus + - Familiarity with coreutils behavior -## Complete the `cp` GNU compatibility +## Expand differential fuzzing for coreutils -Most of the features in `cp` have been implemented by now. -However, some corner cases needs to be implemented. We have 16 remaining failing tests. +The [uutils/coreutils](https://github.com/uutils/coreutils) project has [some fuzzing infrastructure](https://github.com/uutils/coreutils/tree/main/fuzz/fuzz_targets) in place, but many utilities still lack comprehensive fuzz testing. This project focuses on expanding differential fuzzing coverage across coreutils to identify edge cases, improve robustness, and ensure compatibility with GNU coreutils. -To get the list of failing tests, run: -``` -$ ./util/remaining-gnu-error.py |grep "/cp/" -``` +Differential fuzzing compares the behavior of uutils implementations against GNU coreutils to automatically detect discrepancies and bugs that might be missed by traditional testing. -- Difficulty: Medium -- Size: 175 -- Mentors: Sylvestre -- Required skills: +Key areas of work include: +* Creating new fuzz targets for utilities that currently lack them +* Implementing differential fuzzing harnesses that compare uutils vs GNU outputs +* Expanding existing fuzz targets to cover more code paths and options +* Setting up structured fuzzing campaigns with AFL++ and libFuzzer +* Integrating continuous fuzzing into CI/CD workflows +* Triaging and fixing bugs discovered through fuzzing +* Creating a corpus of interesting test inputs for regression testing +* Documenting fuzzing infrastructure and best practices +* Performance profiling of fuzz targets to maximize coverage + +- **Difficulty**: Medium +- **Size**: ~175 hours +- **Mentors**: TBD +- **Required skills**: - Rust - - Basic knowledge about the terminal + - Experience with fuzzing tools (AFL++, libFuzzer, cargo-fuzz) + - Understanding of differential testing methodologies + - Debugging and bug triage skills + - Familiarity with coreutils behavior -## Complete the `mv` GNU compatibility +## Complete `findutils` GNU compatibility -Most of the features in `mv` have been implemented by now. -However, some corner cases needs to be implemented. We have 10 remaining failing tests. +The [uutils/findutils](https://github.com/uutils/findutils) project has made significant progress with [more than half](https://github.com/uutils/findutils-tracking/) of the GNU findutils and BFS tests passing. This project focuses on completing the remaining work to achieve full GNU compatibility and production readiness. -To get the list of failing tests, run: -``` -$ ./util/remaining-gnu-error.py |grep "/mv/" -``` +The goal is to finish implementing missing features, fix failing test cases, and ensure the utilities (`find`, `xargs`, `locate`, etc.) are fully compatible with their GNU counterparts. -- Difficulty: Medium -- Size: 175 -- Mentors: Sylvestre -- Required skills: +Key areas of work include: +* Implementing missing command-line options and predicates for `find` +* Fixing edge cases in file system traversal and symlink handling +* Completing `xargs` implementation with proper argument handling +* Improving performance and memory efficiency +* Setting up fuzzing infrastructure for differential testing +* Implementing fuzz targets similar to the [coreutils fuzzing approach](https://github.com/uutils/coreutils/tree/main/fuzz/fuzz_targets) +* Running and passing remaining GNU test suite cases +* Conducting differential fuzzing against GNU findutils and BFS + +- **Difficulty**: Medium +- **Size**: ~175 hours +- **Mentors**: Sylvestre +- **Required skills**: - Rust - - Basic knowledge about the terminal + - Understanding of file system operations + - Familiarity with `find` and `xargs` usage + - Experience with fuzzing tools is a plus -## Improve `stty` -The `stty` utility is currently only partially implemented and should be expanded. +## Complete `diffutils` GNU compatibility -See issues: [#3859](https://github.com/uutils/coreutils/issues/3859), [#3860](https://github.com/uutils/coreutils/issues/3860), [#3861](https://github.com/uutils/coreutils/issues/3861), [#3862](https://github.com/uutils/coreutils/issues/3862), [#3863](https://github.com/uutils/coreutils/issues/3863). +The [uutils/diffutils](https://github.com/uutils/diffutils) project provides Rust implementations of `diff`, `diff3`, `cmp`, and `sdiff`. Significant progress has been made, but additional work is needed to achieve full GNU compatibility and handle all edge cases. -- Difficulty: Medium -- Size: 175 -- Mentors: Terts Diepraam -- Required skills: +This project focuses on completing the remaining features, fixing compatibility issues, and ensuring all utilities pass the GNU test suite. + +Key areas of work include: +* Implementing missing options and output formats for `diff` +* Improving algorithm efficiency for large file comparisons +* Completing `diff3` three-way merge functionality +* Fixing edge cases in binary file detection and handling +* Supporting all unified and context diff formats +* Running and passing the GNU diffutils test suite +* Performance benchmarking and optimization +* Adding fuzzing infrastructure for differential testing against GNU diffutils + +- **Difficulty**: Medium +- **Size**: ~175 hours +- **Mentors**: TBD +- **Required skills**: - Rust - - Basic knowledge about the terminal + - Understanding of diff algorithms (Myers, Patience, etc.) + - Familiarity with `diff` and patch workflows + - Text processing and parsing + +## Complete the Rust implementation of `sed` + +The `sed` (stream editor) utility is a fundamental Unix tool for parsing and transforming text. A Rust implementation has been started but requires significant work to achieve full compatibility with GNU `sed` and POSIX standards. + +This project focuses on completing the existing Rust `sed` implementation to make it production-ready. The work involves implementing missing commands and flags, fixing edge cases, improving regular expression support, and ensuring the implementation passes the GNU test suite. + +Key areas of work include: +* Implementing missing `sed` commands and addressing flags +* Handling complex regular expressions and backreferences +* Supporting multi-line pattern space operations +* Implementing hold space operations correctly +* Adding support for GNU `sed` extensions +* Fixing edge cases and improving error handling +* Running and passing the GNU `sed` test suite +* Performance optimization and benchmarking against GNU `sed` +* Setting up fuzzing infrastructure for differential testing +* Implementing fuzz targets similar to the [coreutils fuzzing approach](https://github.com/uutils/coreutils/tree/main/fuzz/fuzz_targets) +* Conducting differential fuzzing against GNU `sed` to identify edge cases and bugs -## Improve findutils coverage +- **Difficulty**: Medium +- **Size**: ~175 hours +- **Mentors**: TBD +- **Required skills**: + - Rust + - Understanding of regular expressions + - Familiarity with `sed` usage and scripting + - Text processing and parsing concepts + - Experience with fuzzing tools (AFL++, cargo-fuzz) is a plus + +## Rust implementation of `grep` + +The goal of this project is to create a high-performance, feature-complete Rust implementation of `grep` (GNU grep) as part of the uutils ecosystem. While tools like `ripgrep` exist, this project aims to provide a drop-in replacement for GNU `grep` with full compatibility, including all command-line options, output formats, and edge case behaviors. + +The `grep` utility is one of the most widely-used Unix tools for searching text using patterns. A uutils implementation would need to balance GNU compatibility with the performance advantages that Rust can provide. + +Key aspects of the project include: +* Implementing full POSIX and GNU `grep` command-line interface +* Supporting basic regular expressions (BRE), extended regular expressions (ERE), and Perl-compatible regular expressions (PCRE) +* Implementing all output modes (normal, inverted match, count, files-with-matches, etc.) +* Supporting context lines (-A, -B, -C options) and various formatting options +* Handling binary files, compressed files, and recursive directory search +* Optimizing performance for common use cases while maintaining correctness +* Implementing color output and various line-buffering modes +* Running and passing the GNU `grep` test suite +* Setting up fuzzing infrastructure and differential testing against GNU `grep` +* Performance benchmarking against GNU `grep` and other implementations + +- **Difficulty**: Hard +- **Size**: ~350 hours +- **Mentors**: TBD +- **Required skills**: + - Rust + - Deep understanding of regular expression engines + - Familiarity with `grep` usage and advanced features + - Performance optimization and profiling + - Text processing and I/O optimization techniques -[More than half](https://github.com/uutils/findutils-tracking/) of the findutils GNU & BFS are passing. The goal of this project is to improve the compatibility of uutils/findutils with regard to GNU's implementation. +## Rust implementation of `awk` -See [https://github.com/uutils/findutils](https://github.com/uutils/findutils) +The goal of this project is to create a Rust-based implementation of `awk`, one of the most powerful and widely-used text processing utilities in Unix/Linux systems. The `awk` utility provides a complete programming language for pattern scanning and processing, making it essential for data extraction, report generation, and text transformation tasks. +This implementation would be a standalone project within the uutils ecosystem, similar to how `findutils` and `diffutils` are organized. The primary objectives are to achieve compatibility with POSIX `awk` specification and GNU `awk` (gawk) extensions, while leveraging Rust's performance and safety guarantees. -To achieve this, we should invest in fuzzing findutils: -Just like we are [doing with some](https://github.com/uutils/coreutils/tree/main/fuzz/fuzz_targets) [Coreutils programs](https://github.com/uutils/coreutils/blob/main/.github/workflows/fuzzing.yml), we should: -* fuzz findutils -* do some differential testing with GNU's implementation (and potentially others) +Key aspects of the project include: +* Implementing the `awk` lexer and parser for the AWK programming language +* Building the pattern-action execution engine +* Supporting built-in variables (`NR`, `NF`, `FS`, `RS`, etc.) and functions +* Implementing regular expression matching and field splitting +* Adding support for arrays, user-defined functions, and control flow +* Ensuring compatibility with the POSIX `awk` standard +* Gradually implementing GNU `awk` extensions where feasible +* Setting up GNU test suite execution for validation -- Difficulty: Medium -- Size: 175 -- Mentors: Sylvestre -- Required skills: +- **Difficulty**: Hard +- **Size**: ~350 hours +- **Mentors**: TBD +- **Required skills**: - Rust - - Basic knowledge about the terminal usage + - Understanding of lexers, parsers, and interpreters + - Familiarity with `awk` usage and programming + - Knowledge of regular expressions + - Experience with programming language implementation is a plus + +## Complete `procps` implementation and GNU compatibility + +The [uutils/procps](https://github.com/uutils/procps) project aims to reimplement process and system monitoring utilities in Rust. While initial implementations have been started for various tools, this project focuses on completing the core utilities and achieving production readiness with full GNU compatibility. + +This project focuses on completing the most essential procps utilities (`ps`, `top`, `pgrep`, `pkill`, `free`, `uptime`) and ensuring they are ready for real-world usage. + +Key areas of work include: +* Completing core functionality for essential procps utilities +* Implementing missing command-line options and output formats +* Fixing edge cases in /proc filesystem parsing across different kernel versions +* Ensuring accurate process information gathering and display +* Implementing performance optimizations for tools like `top` and `ps` +* Setting up and running GNU procps test suite +* Adding comprehensive error handling and validation +* Creating fuzzing infrastructure for robust /proc parsing +* Performance benchmarking against GNU procps + +- **Difficulty**: Medium +- **Size**: ~175 hours +- **Mentors**: TBD +- **Required skills**: + - Rust + - Understanding of Linux /proc filesystem + - Familiarity with process management and system monitoring + - Knowledge of procps tools usage + +## Complete `util-linux` implementation and GNU compatibility + +The [uutils/util-linux](https://github.com/uutils/util-linux) project aims to reimplement essential system utilities in Rust. This project focuses on completing the most commonly-used util-linux utilities and achieving production-ready status with full GNU compatibility. + +This project prioritizes completing utilities that are frequently used in scripts and system administration (`dmesg`, `lscpu`, `mount`, `umount`, `kill`, `logger`). + +Key areas of work include: +* Completing implementation of high-priority util-linux utilities +* Implementing missing options and edge case handling +* Ensuring proper interaction with kernel interfaces and system calls +* Supporting various Linux distributions and kernel versions +* Setting up and running GNU util-linux test suite +* Adding comprehensive error handling for system operations +* Performance optimization and resource efficiency +* Creating fuzzing infrastructure for system call interactions +* Documentation and man page compatibility + +- **Difficulty**: Medium +- **Size**: ~175 hours +- **Mentors**: TBD +- **Required skills**: + - Rust + - Understanding of Linux system calls and kernel interfaces + - Familiarity with util-linux utilities + - System administration knowledge + +## Complete `bsdutils` implementation + +The [uutils/bsdutils](https://github.com/uutils/bsdutils) project focuses on reimplementing BSD-origin utilities commonly found on Linux systems. This project aims to complete the core utilities and achieve compatibility with both BSD and GNU/Linux variants. + +This project focuses on completing essential bsdutils tools like `logger`, `script`, `column`, `hexdump`, and `look`, ensuring they work correctly across different Unix-like systems. + +Key areas of work include: +* Completing implementation of core bsdutils utilities +* Ensuring compatibility with both BSD and GNU/Linux behavior +* Implementing missing command-line options and output formats +* Handling cross-platform differences and portability +* Setting up test suites for both BSD and GNU variants +* Adding comprehensive error handling +* Performance optimization and memory efficiency +* Creating fuzzing infrastructure for robust input handling +* Documentation and compatibility notes + +- **Difficulty**: Medium +- **Size**: ~175 hours +- **Mentors**: TBD +- **Required skills**: + - Rust + - Familiarity with both BSD and Linux environments + - Understanding of bsdutils tools + - Cross-platform development experience ## Localization Support for localization for formatting, quoting & sorting in various utilities, like `date`, `ls` and `sort`. For this project, we need to figure out how to deal with locale data. The first option is to use the all-Rust `icu4x` library, which has a different format than what distributions usually provide. In this case a solution _could_ be to write a custom `localedef`-like command. The second option is to use a wrapper around the C `icu` library, which comes with the downside of being a C dependency. @@ -258,20 +442,6 @@ The project aims at integrating the GNU test suite execution using the Rust-base - **Size:**: ~175 hours - **Difficulty:**: Medium -## Refactoring `factor` - -The uutils `factor` is currently significantly slower than -GNU `factor` and only supports numbers up to 2^64-1. See [issue 1559](https://github.com/uutils/coreutils/issues/1559) -and [issue 1456](https://github.com/uutils/coreutils/issues/1456) for more information. - -- Difficulty: Hard -- Size: 175 hours -- Mentors: TBD -- Required skills: - - Rust - - Optimization techniques - - Mathematics - ## Symbolic/Fuzz Testing and Formal Verification of Tool Grammars See [Using Lightweight Formal Methods to Validate a Key Value Storage Node In Amazon S3](https://www.amazon.science/publications/using-lightweight-formal-methods-to-validate-a-key-value-storage-node-in-amazon-s3). diff --git a/scripts/build-docs-l10n.sh b/scripts/build-docs-l10n.sh new file mode 100755 index 000000000..ea47afec2 --- /dev/null +++ b/scripts/build-docs-l10n.sh @@ -0,0 +1,251 @@ +#!/bin/bash +# Build coreutils mdbook docs for all languages +# Usage: build-docs-l10n.sh +# +# Expects: +# - uudoc already built (cargo run --bin uudoc done previously) +# - l10n locales already copied into coreutils/src/uu/*/locales/ +# - English docs already built in coreutils/docs/book/ +# +# For each language, swaps the target locale's .ftl files into en-US.ftl +# (since uudoc hardcodes that filename), re-runs uudoc, then builds mdbook. + +set -euo pipefail + +COREUTILS_DIR="$(cd "${1:?Usage: $0 }" && pwd)" + +# Convert FTL locale code to URL code: strip region when language == region +# (e.g., fr-FR -> fr, es-ES -> es) but keep distinct ones (zh-Hans, pt-BR, nb-NO) +ftl_to_url() { + local code="$1" + local lang="${code%%-*}" + local region="${code#*-}" + if [ "${region,,}" = "${lang,,}" ]; then + echo "$lang" + else + echo "$code" + fi +} + +# Discover available locales from the coreutils source (l10n already copied in) +# Use ls utility as reference +declare -A LANG_MAP=() +for ftl in "$COREUTILS_DIR"/src/uu/ls/locales/*.ftl; do + [ -f "$ftl" ] || continue + ftl_name=$(basename "$ftl" .ftl) + [ "$ftl_name" = "en-US" ] && continue + url_code=$(ftl_to_url "$ftl_name") + LANG_MAP[$url_code]="$ftl_name" +done + +echo "Found ${#LANG_MAP[@]} locales to build: ${!LANG_MAP[*]}" + +TMPDIR=$(mktemp -d) +trap 'rm -rf "$TMPDIR"' EXIT + +# Save a copy of all en-US.ftl files for restoration +cp -r "$COREUTILS_DIR/src" "$TMPDIR/src-backup" + +# Find uudoc binary (already built by the English docs step) +UUDOC="$COREUTILS_DIR/target/debug/uudoc" +if [ ! -x "$UUDOC" ]; then + UUDOC="$COREUTILS_DIR/target/release/uudoc" +fi + +# Save English tldr.zip for restoration +EN_TLDR="$TMPDIR/tldr-en.zip" +cp "$COREUTILS_DIR/docs/tldr.zip" "$EN_TLDR" 2>/dev/null || true + +# Download and repack translated tldr archives (uudoc expects pages/ prefix) +# Merge with English so missing examples fall back to English +echo "Downloading translated tldr archives..." +EN_TLDR_DIR="$TMPDIR/tldr-en-dir" +if [ -f "$EN_TLDR" ]; then + mkdir -p "$EN_TLDR_DIR" + (cd "$EN_TLDR_DIR" && unzip -o "$EN_TLDR" > /dev/null 2>&1) +fi +for lang in "${!LANG_MAP[@]}"; do + raw="$TMPDIR/tldr-raw-${lang}.zip" + curl -sfL "https://github.com/tldr-pages/tldr/releases/download/v2.3/tldr-pages.${lang}.zip" \ + -o "$raw" || true + if [ -f "$raw" ]; then + repack_dir="$TMPDIR/tldr-repack-${lang}" + mkdir -p "$repack_dir/pages" + (cd "$repack_dir" && unzip -o "$raw" -d pages/ > /dev/null 2>&1) + + # Record which utilities have translated examples (before merging with English) + translated_list="$TMPDIR/tldr-translated-${lang}.list" + (cd "$repack_dir" && find pages -name "*.md" -printf '%f\n' | sed 's/\.md$//' | sort -u > "$translated_list") + + # Merge: start with English, overlay translated on top + if [ -d "$EN_TLDR_DIR" ]; then + merge_dir="$TMPDIR/tldr-merge-${lang}" + cp -r "$EN_TLDR_DIR" "$merge_dir" + cp -r "$repack_dir/pages"/* "$merge_dir/pages/" 2>/dev/null || true + (cd "$merge_dir" && zip -r "$TMPDIR/tldr-${lang}.zip" pages/ > /dev/null 2>&1) + rm -rf "$merge_dir" + else + (cd "$repack_dir" && zip -r "$TMPDIR/tldr-${lang}.zip" pages/ > /dev/null 2>&1) + fi + rm -rf "$repack_dir" "$raw" + fi +done + +# Merge translated FTL with English: translated keys take priority, +# English keys fill in any gaps (handles empty files, partial translations). +# Sets MERGE_HAD_FALLBACK=1 if any English fallback entries were added. +merge_ftl() { + local english="$1" + local translated="$2" + local output="$3" + MERGE_HAD_FALLBACK=0 + + # If translated file is empty or missing, keep English as-is + if [ ! -s "$translated" ]; then + cp "$english" "$output" + MERGE_HAD_FALLBACK=1 + return 0 + fi + + # Extract top-level message IDs from the translated file + # (lines starting with identifier = ...) + local translated_keys + translated_keys=$(grep -oP '^[a-zA-Z][a-zA-Z0-9_-]*(?=\s*=)' "$translated" || true) + + # Start with the translated content + cp "$translated" "$output" + + # Append English entries whose keys are NOT in the translated file + local current_key="" + local entry_lines="" + while IFS= read -r line || [ -n "$line" ]; do + if [[ "$line" =~ ^[a-zA-Z][a-zA-Z0-9_-]*[[:space:]]*= ]]; then + # Flush previous entry if it was missing from translation + if [ -n "$current_key" ] && ! echo "$translated_keys" | grep -qxF "$current_key"; then + printf '%s\n' "$entry_lines" >> "$output" + MERGE_HAD_FALLBACK=1 + fi + # Extract just the identifier + current_key=$(echo "$line" | grep -oP '^[a-zA-Z][a-zA-Z0-9_-]*') + entry_lines="$line" + elif [[ "$line" =~ ^[[:space:]] ]] && [ -n "$current_key" ]; then + # Continuation line (indented = part of current entry) + entry_lines="$entry_lines"$'\n'"$line" + else + # Blank line or comment — flush previous entry if needed + if [ -n "$current_key" ] && ! echo "$translated_keys" | grep -qxF "$current_key"; then + printf '%s\n' "$entry_lines" >> "$output" + MERGE_HAD_FALLBACK=1 + fi + current_key="" + entry_lines="" + fi + done < "$english" + # Flush last entry + if [ -n "$current_key" ] && ! echo "$translated_keys" | grep -qxF "$current_key"; then + printf '%s\n' "$entry_lines" >> "$output" + MERGE_HAD_FALLBACK=1 + fi +} + +restore_en() { + # Restore all en-US.ftl files from backup + for util_dir in "$COREUTILS_DIR"/src/uu/*/locales/; do + util=$(basename "$(dirname "$util_dir")") + backup="$TMPDIR/src-backup/uu/$util/locales/en-US.ftl" + if [ -f "$backup" ]; then + cp "$backup" "${util_dir}en-US.ftl" + fi + done + if [ -f "$TMPDIR/src-backup/uucore/locales/en-US.ftl" ]; then + cp "$TMPDIR/src-backup/uucore/locales/en-US.ftl" "$COREUTILS_DIR/src/uucore/locales/en-US.ftl" + fi + # Restore English tldr + if [ -f "$EN_TLDR" ]; then + cp "$EN_TLDR" "$COREUTILS_DIR/docs/tldr.zip" + fi +} + +cd "$COREUTILS_DIR" + +for lang in "${!LANG_MAP[@]}"; do + echo "=== Building $lang docs ===" + ftl_name="${LANG_MAP[$lang]}" + + # Swap in translated tldr.zip (fall back to English if unavailable) + if [ -f "$TMPDIR/tldr-${lang}.zip" ]; then + cp "$TMPDIR/tldr-${lang}.zip" docs/tldr.zip + fi + + # uudoc hardcodes en-US.ftl — merge translated locale into en-US.ftl + # so that untranslated keys fall back to English + # Track which utilities needed English fallback + declare -A fallback_utils=() + for util_dir in src/uu/*/locales/; do + if [ -f "${util_dir}${ftl_name}.ftl" ]; then + util=$(basename "$(dirname "$util_dir")") + en_backup="$TMPDIR/src-backup/uu/$util/locales/en-US.ftl" + merge_ftl "$en_backup" "${util_dir}${ftl_name}.ftl" "${util_dir}en-US.ftl" + if [ "$MERGE_HAD_FALLBACK" = "1" ]; then + fallback_utils[$util]=1 + fi + fi + done + if [ -f "src/uucore/locales/${ftl_name}.ftl" ]; then + uucore_en_backup="$TMPDIR/src-backup/uucore/locales/en-US.ftl" + merge_ftl "$uucore_en_backup" "src/uucore/locales/${ftl_name}.ftl" "src/uucore/locales/en-US.ftl" + fi + + # Re-generate markdown with swapped locale + if ! "$UUDOC" 2>&1 | tail -3; then + echo "WARNING: uudoc failed for $lang, skipping" + restore_en + continue + fi + + # Inject translation notice into utility pages that have untranslated strings + # Convert ftl_name to Weblate language code (hyphens -> underscores) + weblate_lang="${ftl_name//-/_}" + for util in "${!fallback_utils[@]}"; do + md_file="docs/src/utils/${util}.md" + if [ -f "$md_file" ]; then + notice="
Some strings on this page have not been translated yet. You can help by translating them on Weblate.
" + # Insert notice after the first line (# utility-name) + sed -i "1a\\${notice}" "$md_file" + fi + done + if [ ${#fallback_utils[@]} -gt 0 ]; then + echo " Added translation notice to ${#fallback_utils[@]} utilities with untranslated strings" + fi + + # Inject notice into Examples section for utilities whose examples fell back to English + translated_list="$TMPDIR/tldr-translated-${lang}.list" + if [ -f "$translated_list" ]; then + examples_fallback=0 + for md_file in docs/src/utils/*.md; do + [ -f "$md_file" ] || continue + util=$(basename "$md_file" .md) + # Only process files that have an Examples section + if grep -q "^## Examples" "$md_file" && ! grep -qxF "$util" "$translated_list"; then + # This utility's examples came from English fallback + sed -i '/^## Examples$/a\ +
The examples have not been translated yet and are shown in English. You can help by translating them on tldr-pages.
' "$md_file" + examples_fallback=$((examples_fallback + 1)) + fi + done + if [ "$examples_fallback" -gt 0 ]; then + echo " Added example translation notice to $examples_fallback utilities" + fi + fi + + # Build mdbook to a language-specific output directory + sed -i '/^multilingual/d' docs/book.toml + (cd docs && mdbook build -d "book-${lang}") + + # Restore en-US.ftl files for next iteration + restore_en + + echo "Built $lang docs in docs/book-${lang}/" +done + +echo "All translated docs built." diff --git a/scripts/patch-mdbook-theme.sh b/scripts/patch-mdbook-theme.sh new file mode 100755 index 000000000..04d16cd9e --- /dev/null +++ b/scripts/patch-mdbook-theme.sh @@ -0,0 +1,170 @@ +#!/bin/bash +# Patch mdbook theme to add language selector and utility links +# Usage: patch-mdbook-theme.sh + +set -euo pipefail + +DOCS_DIR="${1:?Usage: $0 }" +L10N_DIR="${2:?Usage: $0 }" + +HEAD_HBS="$DOCS_DIR/theme/head.hbs" + +# Convert FTL locale code to URL code: strip region when language == region +# (e.g., fr-FR -> fr, es-ES -> es) but keep distinct ones (zh-Hans, pt-BR, nb-NO) +ftl_to_url() { + local code="$1" + local lang="${code%%-*}" + local region="${code#*-}" + # If region is the language uppercased (fr-FR, es-ES, etc.), simplify to just the language + if [ "${region,,}" = "${lang,,}" ]; then + echo "$lang" + else + echo "$code" + fi +} + +# Generate display name for a locale code +# Uses python3+babel if available, otherwise falls back to the code itself +locale_display_name() { + local code="$1" + if command -v python3 > /dev/null 2>&1; then + local name + name=$(python3 -c " +try: + from babel import Locale + print(Locale.parse('${code}'.replace('-', '_')).get_display_name()) +except Exception: + print('${code}') +" 2>/dev/null) + # Capitalize first letter for consistency + echo "${name^}" + else + echo "$code" + fi +} + +# Scan l10n repo to find which locales have translations +# Use a representative utility (ls) to find available locales +LANGS_JSON="['en', 'English']" +for ftl in "$L10N_DIR"/src/uu/ls/locales/*.ftl; do + [ -f "$ftl" ] || continue + ftl_name=$(basename "$ftl" .ftl) + [ "$ftl_name" = "en-US" ] && continue + + url_code=$(ftl_to_url "$ftl_name") + display=$(locale_display_name "$ftl_name") + LANGS_JSON="$LANGS_JSON, ['$url_code', '$display']" +done + +# Append styles and JS to head.hbs +cat >> "$HEAD_HBS" << 'ENDSTYLE' + +ENDSTYLE +cat >> "$HEAD_HBS" << 'ENDSCRIPT' + +ENDSCRIPT + +# Inject the dynamically-built language list +sed -i "s|LANGS_PLACEHOLDER|[${LANGS_JSON}]|" "$HEAD_HBS" + +echo "Patched $HEAD_HBS with language selector and utility links" diff --git a/static/logo-dark.svg b/static/logo-dark.svg new file mode 100644 index 000000000..dee38a04f --- /dev/null +++ b/static/logo-dark.svg @@ -0,0 +1,61 @@ + diff --git a/static/style.css b/static/style.css index 135b7fb4e..1214b0641 100644 --- a/static/style.css +++ b/static/style.css @@ -1,20 +1,50 @@ :root { + /* Light theme colors (default) */ + + --accent-color: #c04828; + --dark-fg-color: #fff; --light-fg-color: #141414; --light-bg-color: var(--dark-fg-color); --dark-bg-color: var(--light-fg-color); --fg-color: var(--light-fg-color); --bg-color: var(--light-bg-color); - --light-link-color: #c04828; - --dark-link-color: #c04828; - --link-color: var(--light-link-color); + --link-color: var(--accent-color); --light-highlight-bg-color: #ededed; --light-highlight-fg-color: #595959; --dark-highlight-bg-color: #27272a; --dark-highlight-fg-color: #ededed; --highlight-fg-color: var(--light-highlight-fg-color); --highlight-bg-color: var(--light-highlight-bg-color); + --link-text-color: var(--accent-color); + --header-border-color: #ddd; + --post-bg-color: #e5e5e5; --font-face: "Fira Sans", sans-serif; + + --github-icon: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='%23fff' d='M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12'/%3E%3C/svg%3E"); + --github-icon-black: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='000' d='M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12'/%3E%3C/svg%3E"); +} + +@media (prefers-color-scheme: dark) { + :root { + --fg-color: #e1e1e1; + --bg-color: #222222; + --link-color: var(--accent-color); + --light-highlight-bg-color: #2d2d2d; + --light-highlight-fg-color: #ffffff; + --dark-highlight-bg-color: #27272a; + --dark-highlight-fg-color: #ededed; + --highlight-fg-color: var(--light-highlight-fg-color); + --highlight-bg-color: var(--light-highlight-bg-color); + --link-text-color: var(--accent-color); + --header-border-color: #404040; + --post-bg-color: #2d2d2d; + } +} + +body { + background-color: var(--bg-color); + color: var(--fg-color); } *, @@ -89,7 +119,7 @@ header { justify-items: center; padding: 0.5rem 2rem; width: 100%; - border-bottom: 1px solid #ddd; + border-bottom: 1px solid var(--header-border-color); font-size: 1.2rem; } @@ -111,13 +141,12 @@ header .home svg { } header a { - color: black; + color: var(--fg-color); border-bottom: 2px solid transparent; } header a:hover:not(.home) { - color: black; - border-bottom: 2px solid #c04828; + border-bottom: 2px solid var(--link-text-color); } .navigation-block { @@ -149,13 +178,13 @@ header .icon { #mobile-open-navigation button div { margin: 0.5em 0; width: 2em; - border-bottom: 0.25em solid black; + border-bottom: 0.25em solid var(--fg-color); } header { grid-template-columns: max-content 1fr; } - + .spacer { display: none; } @@ -165,7 +194,7 @@ header .icon { grid-column: auto / span 2; justify-self: left; } - + header:not(.open) .spacer, header:not(.open) .navigation-block { display: none; @@ -273,8 +302,8 @@ ul { /* FOOTER */ footer { align-items: center; - background-color: var(--fg-color); - color: var(--bg-color); + background-color: var(--light-fg-color); + color: var(--light-bg-color); display: flex; flex-grow: 0; flex-shrink: 1; @@ -286,17 +315,23 @@ footer { } .github-icon { - background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='%23fff' d='M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12'/%3E%3C/svg%3E"); + background-image: var(--github-icon); height: 1.25rem; width: 1.25rem; } .github-icon-black { - background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='000' d='M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12'/%3E%3C/svg%3E"); + background-image: var(--github-icon-black); height: 1em; width: 1em; } +@media (prefers-color-scheme: dark) { + .github-icon-black { + background-image: var(--github-icon); + } +} + .projects { display: flex; flex-direction: column; @@ -325,13 +360,13 @@ footer { margin-bottom: 0; } -.project>span { +.project > span { color: transparent; transition: color 0.3s; } -.project:hover>span { - color: black; +.project:hover > span { + color: var(--fg-color); } .project:hover { @@ -342,6 +377,7 @@ footer { font-size: 3em; font-weight: 900; margin-bottom: 0.5em; + text-transform: capitalize; } @media (min-width: 640px) { @@ -353,21 +389,21 @@ footer { .details { margin-bottom: 1.5em; - color: #333; + color: var(--fg-color); } .post-thingy { display: block; padding: 1em; - color: black; - background: #e5e5e5; + color: var(--fg-color); + background: var(--post-bg-color); border-radius: 0.3em; - border: 0.2em solid #e5e5e5; + border: 0.2em solid var(--post-bg-color); margin-bottom: 0.5em; } .post-thingy:hover { - border-color: #c04828; + border-color: var(--link-text-color); background: transparent; } @@ -382,6 +418,7 @@ blockquote { .links { display: flex; + flex-wrap: wrap; justify-content: stretch; gap: 1em; margin-bottom: 2em; @@ -390,8 +427,14 @@ blockquote { .links > a { padding: 0.2em 1em; - color: #c04828; + color: var(--link-text-color); border: 2px solid #c04828; flex: 1; text-align: center; } + +.links > a:hover { + color: var(--dark-fg-color); + background-color: #c04828; + border-color: #c04828; +} diff --git a/templates/base.html b/templates/base.html index 61e9395ab..c6d86070d 100644 --- a/templates/base.html +++ b/templates/base.html @@ -10,6 +10,8 @@ + + @@ -23,13 +25,13 @@