diff --git a/.gitattributes b/.gitattributes index 628aff4d6..75df29b5f 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,4 +1,3 @@ -# Ignore the following directories when showing which languages -# difftastic is implemented in on GitHub. +# diffr is implemented in Rust; keep GitHub's language stats honest. sample_files/** linguist-vendored vendored_parsers/** linguist-vendored diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 4edd6ac37..38c66e948 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -11,6 +11,6 @@ Thanks for reporting a bug! Please include all of the following: (1) A description of the issue. A screenshot is often helpful too. -(2) A copy of what you're diffing. If you're diffing files, include the before and after files. If you're using difftastic with a VCS repository (e.g. git), include the URL and commit hash. +(2) A copy of what you're diffing. If you're diffing files, include the before and after files. If you're using diffr with a Git repository, include the URL and commit hash. -(3) The version of difftastic you're using (see `difft --version`) and your operating system. +(3) The version of diffr you're using (see `diffr --version`) and your operating system. diff --git a/.github/workflows/deploy_docs.yml b/.github/workflows/deploy_docs.yml deleted file mode 100644 index 9158fd4fd..000000000 --- a/.github/workflows/deploy_docs.yml +++ /dev/null @@ -1,62 +0,0 @@ -name: Deploy Manual - -on: - push: - branches: - - master - -jobs: - pre_deploy: - runs-on: ubuntu-22.04 - - outputs: - should_skip: ${{ steps.skip_check.outputs.should_skip }} - steps: - - id: skip_check - uses: fkirc/skip-duplicate-actions@f75f66ce1886f00957d99748a42c724f4330bdcf # v5 - with: - concurrent_skipping: always - - deploy: - needs: pre_deploy - if: needs.pre_deploy.outputs.should_skip != 'true' - runs-on: ubuntu-22.04 - steps: - # v4.2.2 - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 - - - name: Install jq - run: sudo apt-get install -y jq - - - uses: dtolnay/rust-toolchain@1.76.0 - - run: cargo doc - - - name: Setup mdBook - uses: peaceiris/actions-mdbook@ee69d230fe19748b7abf22df32acaa93833fad08 # v2 - with: - mdbook-version: '0.5.2' - - - name: Build manual - run: mdbook build - working-directory: manual - - - name: Build translated manual - run: mdbook build - working-directory: translation/zh-CN/manual-zh-CN - - - name: Add rustdoc output - run: cp -r target/doc manual/book/rustdoc - - - name: Add translated manual output - run: cp -r translation/zh-CN/manual-zh-CN/book manual/book/zh-CN - - - name: Add homepage - run: cp -r homepage/* manual/book/ - - - name: Deploy to GitHub pages - uses: JamesIves/github-pages-deploy-action@920cbb300dcd3f0568dbc42700c61e2fd9e6139c # v4.6.4 - with: - branch: gh-pages - folder: manual/book - single-commit: true - force: true diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index d08c5c0ab..4f9f60c53 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -7,42 +7,32 @@ on: jobs: create-release: + permissions: + contents: write runs-on: ubuntu-22.04 steps: # v4.2.2 - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 - uses: taiki-e/create-gh-release-action@eba8ea96c86cca8a37f1b56e94b4d13301fba651 # v1 with: - # Create a draft release so we can add the changelog before publishing it - # so the changelog is included in the release email - draft: true + # Publish immediately: Review's build downloads the assets by tag. + draft: false env: # (required) GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} upload-assets: + needs: create-release + permissions: + contents: write strategy: fail-fast: false matrix: include: - # Targets that match the OS of the runner. - - target: x86_64-unknown-linux-gnu - os: ubuntu-22.04 - - target: x86_64-pc-windows-msvc - os: windows-latest - target: aarch64-apple-darwin os: macos-latest - - # Targets using cross-compilation (upload-rust-binary-action - # detects that they need cross). - - target: x86_64-unknown-linux-musl - os: ubuntu-22.04 - - target: aarch64-unknown-linux-gnu + - target: x86_64-unknown-linux-gnu os: ubuntu-22.04 - - target: aarch64-pc-windows-msvc - os: windows-latest - - target: x86_64-apple-darwin - os: macos-latest runs-on: ${{ matrix.os }} steps: # v4.2.2 @@ -63,12 +53,3 @@ jobs: env: # (required) GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - push_crates_io: - runs-on: ubuntu-22.04 - steps: - # v4.2.2 - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 - - uses: katyo/publish-crates@02cc2f1ad653fb25c7d1ff9eb590a8a50d06186b # v2 - with: - registry-token: ${{ secrets.CARGO_REGISTRY_TOKEN }} diff --git a/.gitignore b/.gitignore index 12465665a..0b191a4af 100644 --- a/.gitignore +++ b/.gitignore @@ -14,6 +14,3 @@ plugin.wasm # The bundled WASM summarizer ships ready to embed without a WASM toolchain. !/plugins/summarize/plugin.wasm /crates/*/target - -# Generated data left behind by the retired review web viewer. -/examples/review/viewer/data/ diff --git a/.typos.toml b/.typos.toml index 6bd14b854..b5c05f188 100644 --- a/.typos.toml +++ b/.typos.toml @@ -2,10 +2,7 @@ extend-exclude = [ "vendored_parsers/", "sample_files/", "src/tags/linguist/", - "homepage/home_static/demo.cast", "homepage/home_static/*.min.js", - "homepage/home_img", "demo_files/", - "difft.1", # Git index lines carry blob hashes that can spell words. "examples/review/real/*/change.patch", ] diff --git a/AGENTS.md b/AGENTS.md index 372bd736f..108693a0f 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,3 +1,3 @@ -All AI contributions to difftastic must follow AI_POLICY.md. +All AI contributions to diffr must follow AI_POLICY.md. Do not update CHANGELOG.md unless the user explicitly requests it. diff --git a/AI_POLICY.md b/AI_POLICY.md index 9d5668a77..cae155a62 100644 --- a/AI_POLICY.md +++ b/AI_POLICY.md @@ -1,4 +1,4 @@ -Difftastic's AI policy is based on the [LLVM AI Tool Use +diffr's AI policy is based on the [LLVM AI Tool Use Policy](https://llvm.org/docs/AIToolPolicy.html). **Understanding**: You can use any coding tool you like, but you need to read diff --git a/CHANGELOG.md b/CHANGELOG.md index 1c2eadecd..ad58640f5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,2064 +1,18 @@ -## 0.71 (unreleased) +# Changelog -### Diffing +diffr's history before this file begins is difftastic's; see +https://github.com/Wilfred/difftastic/blob/master/CHANGELOG.md for releases +up to 0.71. -Improved linear diffing performance by switching from Wu-Manber to the -Histogram algorithm. Runtime is slightly improved on average and worst -case memory usage is substantially improved. +## 0.1.0 -(Linear diffing is used for line-based diffing and word highlighting -in difftastic. Some diff results have slightly changed due to this -algorithm change.) +First public release of diffr as its own project. -### Parsing - -Improved C++, Dockerfile, Haskell, JavaScript, Perl, Ruby, Rust, Scala and -TypeScript. - -Improved heuristics and the default globs used for language detection. - -Removed Hare support (upstream parser is no longer maintained). - -### Command Line Interface - -`--context` can now be set with the short flag `-c`. - -## 0.70 (released 7th August 2026) - -### Diffing - -Improved diffing performance, particularly when diffing directories. - -### Parsing - -Files with parse errors now report the position of the first error, to -help investigate issues. - -Added support for Dockerfiles and Fish shell. - -Improved support for Dart, Emacs Lisp, Erlang, Java, OCaml, PHP, -Protocol Buffers and TOML. - -Removed support for Elvish and SCSS (upstream parsers are no longer -maintained). - -### Display - -Fixed an issue where files with tabs were not always aligned correctly -in some build configurations. - -Fix an alignment issue with line numbers in side-by-side mode. - -### Release - -Fixed an issue where prebuilt binaries on GitHub did not respect -Cargo.lock, so they used newer library versions than tested on -CI. This caused rendering bugs in source code with tabs. - -## 0.69 (released 30th April 2026) - -## Diffing - -Difftastic now understands when trailing punctuation isn't -significant, so `foo(1,)` and `foo(1)` are treated as "no syntactic -changes". This is supported for Go, Java, JavaScript, Python, Rust, -Swift and TypeScript. - -### Parsing - -Added support for Assembly. - -Substantially improved parsing for Perl. - -Improved parsing for Clojure, Common Lisp, CSS, Dart, Erlang, F#, OCaml, Python, -Rust, Scala, TypeScript and VHDL. - -Removed support for Hack, as the upstream parser is no longer -maintained. `.php` files starting with `` delimiters in C++ and Rust. - -### Diffing - -Difftastic will now split files that contain obviously unchanged -regions, substantially improving performance when a file has multiple -changes that have many unchanged items between them. - -Improved diff results when choosing between syntax nodes at different -nesting levels. This is restoring a heuristic that was removed in -0.20. - -Improved diff results when lists have unequal sizes. - -Improved diff results when the language parser thinks that names occur -in different syntactic positions. - -Adjusted the heuristics for 'so much has changed in this expression -that it is confusing to highlight the unchanged parts'. The heuristic -is now less aggressive, which helps performance and seems to produce -slightly better results. - -## 0.21 (released 28th February 2022) - -### Parsing - -Difftastic now understands `-*-` file headers (as used by Emacs) when -performing language detection. - -### Display - -Improved alignment logic. This fixes a bug where the last line of a -file wasn't displayed, and generally improves how difftastic chooses -to align content. - -Fixed a crash when line wrapping produced an entirely blank line. - -### Diffing - -Improved word diffing (in both comments and line-oriented diffs) when -the source contains Unicode characters. Word splitting now uses the -Unicode alphabetic property. - -Fixed a crash when comments contained multibyte Unicode characters. - -## 0.20 (released 20th February 2022) - -### Diffing - -Diffing now correctly handles nodes being moved to parent -lists. Previously this would be ignored, leading to difftastic -incorrectly claiming things were unchanged. This also leads to better -diffing results in general, although is somewhat slower (2x in -testing). - -Improved slider logic in larger expressions. - -Increased the default value DFT_NODE_LIMIT to 100,000 (from -50,000). This increases the likelihood that files get a syntactic diff -whilst still having acceptable performance. - -### Display - -Fixed an issue where whole file additions/removals were printed twice. - -Fixed an issue where difftastic didn't show context on hunks where the -unchanged content was on different lines. - -Hunks are now merged if the lines are immediately adjacent -(e.g. hunk 1 ends on line 11, hunk 2 starts on line 12), not just if -they're overlapping. - -### Command Line Interface - -Difftastic will now use a text dif for large files that are too big to -parse in a reasonable amount of time. This threshold is -configurable with `--byte-limit` and `DFT_BYTE_LIMIT`. - -Fixed a crash when called with zero arguments. - -## 0.19 (released 7th February 2022) - -### Parsing - -Fixed an issue with changes being ignored in OCaml's `{||}` string -literals. - -### Display - -Fixed an issue where larger additions were not lined up with removals. - -Improved syntax highlighting for Clojure, Common Lisp and TypeScript. - -Comments are now highlighted with italics, making it easier to see -syntax even when text is red. - -Built-in constants are now highlighted consistently with other -constants. - -Improved minor display issues when one file is longer than the other. - -### Diffing - -If given binary files, difftastic will now report if the file contents -are identical. - -Difftastic will now use a line-oriented diff for large files, rather -than trying to use more memory than is available. This threshold is -configurable with `--node-limit` and `DFT_NODE_LIMIT`. - -Fixed a bug in the line-oriented diff logic where lines weren't shown -if they did not have both word additions and word removals. - -### Command Line Interface - -Difftastic will now error if either argument does not exist, unless -`--missing-as-empty` (new argument) is passed. This is a better -default, but requires Mercurial uses to [specify this -flag](https://difftastic.wilfred.me.uk/mercurial.html) in their -configuration. - -## 0.18.1 (released 30 January 2022) - -Fixed a compilation issue on Rust 1.54 (0.18 only built on newer -versions of Rust). - -## 0.18 (released 30 January 2022) - -### Parsing - -Fixed an issue with missing positions in OCaml attribute syntax. - -Fixed parsing issues in Common Lisp: character literals, `loop` macro -usage with `maximizing`. - -### Diffing - -Improved performance when diffing a single large expression. - -### Display - -Fixed display issues where lines were printed more than once. - -Subword changes in comments are now shown in bold, to make them more -visible. - -Improved colours on terminals with light coloured backgrounds. - -### Command Line Interface - -Added a `--width` option which allows overriding `DFT_WIDTH`, and is -more discoverable. - -Added a `--color` option which allows explicitly enabling/disabling -colour output. - -Added a `--background` option which controls whether difftastic uses -bright or dark colours. This can also be controlled by -`DFT_BACKGROUND`. - -Added a `--skip-unchanged` option which suppresses printing for files -that have no changes. - -## 0.17 (released 25 January 2022) - -### Diffing - -Improved performance when all file changes are close together. - -Fixed a bug where syntax after the last changed item was incorrectly -marked as added. - -### Display - -Added syntax highlighting for unchanged comments, strings and types. - -Fixed a bug (introduced in 0.15) where identical text files were -reported as binary files. - -## 0.16 (released 22 January 2022) - -### Parsing - -Whitespace in JSX is parsed more closely to React's whitespace -trimming rules. - -Fixed parsing of heredocs in shell scripts. They are now treated as -string literals. - -Fixed parsing of type variables and tags in OCaml. - -Improved language detection for files with bash/sh syntax. - -### Integration - -Fixed a crash when on Mercurial diffs when a whole file has been -removed. - -### Display - -Improved display performance when there are a large number of hunks. - -Fixed several issues where lines were displayed more than once in a -hunk. - -Fixed an issue where the first changed line was not displayed. - -### Diffing - -Improved diffing performance (both time and memory usage). - -Sliders are now fixed up after diffing. This produces better looking -results in more cases, and makes the primary diffing faster. - -Fixed some corner cases in the line parser where it would match up -isolated newline character as unchanged, leading to weird alignment. - -## 0.15 (released 6 January 2022) - -### Parsing - -Moved to the [official Elixir -parser](https://github.com/elixir-lang/tree-sitter-elixir). - -Updated the Bash, C, C++, C#, Haskell, Java, OCaml, Python, Ruby and -TypeScript parsers to the latest upstream version. - -Fixed a parsing performance regression introduced in 0.13. - -### Diffing - -Line-oriented diffing now has a standalone implementation rather than -reusing structural diff logic. This is significantly faster and -highlighted better. - -Improved performance when diffing two identical files. This is common -when diffing directories. - -### Display - -Improved highlighting heuristics for added/removed blank lines. - -Fixed an alignment bug where the last line being novel would lead to -poor alignment of unchanged lines. - -Fixed minor formatting issues when reporting that a file is binary. - -Improved display performance on large files. - -## 0.14 (released 27 December 2021) - -### Parsing - -Improved language detection if a file has a recognised filename -(e.g. `Rakefile`) or a shebang (e.g. `#!/usr/bin/env node`). - -### Display - -Display width can now be overridden by setting the environment -variable DFT_WIDTH. - -Fixed terminal width calculations on Windows. - -Fixed crash when only one side has changes, but the other side has -additional blank lines. - -Fixed crash on displaying unicode characters on line boundaries. - -### Build - -Fixed some build issues on Windows. - -## 0.13 (released 4 December 2021) - -### Parsing - -Added Bash, Common Lisp and Ruby support. - -Updated the C, CSS and JSON parsers to the latest upstream versions. - -Expanded filename associations, so difftastic recognises more files. - -Improved parsing for regex and template string literals in JavaScript -and TypeScript. - -Improved parsing for float values in CSS. - -Improved word diffing on punctuation in comments. - -When logging is enabled (e.g. `RUST_LOG=warn`), difftastic now warns -on syntax errors. Difftastic is intended to be robust against syntax -errors, so this is primarily intended for parser debugging. - -### Build - -Difftastic now requires fewer C compiler flags, so it should build in -more environments (e.g. compiling with MSVC). - -## 0.12 (released 19 November 2021) - -### Display - -Every hunk is now shown with the file name and a hunk number. This -makes it easier to see which file you're looking at when there are -many changes. - -Keywords in added/removed regions are now shown in bold, to give -modified regions basic syntax highlighting. Previously, all -added/removed regions were bold. - -Lines with changes are now shown in a different colour in side-by-side -display. - -The display logic has been written in terms of a `Hunk` type. This -produces more accurate context, with better alignment, especially when -the context contains blank lines. - -If only a single side has changes (e.g. additions but no removals), -only one column is shown, to maximise display usage. - -Difftastic now wraps rather than truncating lines that are too long -for the terminal width. - -If a file has no syntactic changes, difftastic now shows the file name -consistently with changed files. - -### Command Line Interface - -The difftastic binary is now named `difft`, to reduce typing during -usage. - -### Parsing - -Updated to latest upstream Haskell parser ([commit -d72f2e4](https://github.com/tree-sitter/tree-sitter-haskell/commit/d72f2e42c0d5ccf8e8b1c39e3642428317e8fe02)). - -### Diffing - -Fixed a bug when diffing multiline comments where unchanged parts were -not highlighted correctly. - -## 0.11 (released 18 October 2021) - -### Parsing - -Improved handling of paired delimiters, particularly in C, C++ and C#. - -Improved word splitting in when diffing similar comments (it's now -more granular). - -Fixed a rare issue where single-item lists were flattened. - -### Diffing - -Diff calculations are now greedier when syntax nodes are identical, making -diffing significantly faster when most syntax nodes are the same. - -### Integration - -Added support for Mercurial, see [this section in the -manual](http://difftastic.wilfred.me.uk/getting_started.html#mercurial-external-diffs) -for instructions. - -### Display - -Added basic syntax highlighting for comments (dimmed) and keywords -(bold) in unchanged source code. - -Characters that don't have a position in the parsed syntax tree are -now displayed in purple, to make bugs more obvious. Previously they -were dimmed. - -## 0.10.1 (released 28 September 2021) - -### Build - -Fix compilation on macOS where the C++ compiler defaulted to a -version of C++ older than C++14. - -## 0.10 (released 24 September 2021) - -### Parsing - -Added a C parser. - -Added a C++ parser. Difftastic prefers the C++ parser for `.h` -files. Please file a bug if you see issues. - -Added a C# parser. - -Added a Haskell parser. - -Removed legacy regex-based parsing backend. - -### Diffing - -Some additional runtime optimisations. - -### Manual - -Added a chapter on difficult cases for tree diff algorithms. - -## 0.9 (released 14 September 2021) - -### Parsing - -Added TypeScript parser and TSX parser. Added Elixir parser. - -The following extensions are now associated with Clojure: `.bb`, -`.boot`, `.clj`, `.cljc`, `.clje`, `.cljs`, `.cljx`, `.edn`, `.joke` -and `.joker`. - -Fixed an issue with parsing integer values in CSS with units, -e.g. `123px`. - -Improved parsing of Rust punctuation like `&` and `::` inside macro -invocations. Improved handling of `|closure_param|` and `[` `]` -delimiters in Rust. - -The line-based parser for text files now uses word-level diffs. - -### Diffing - -Optimised Dijkstra implementation, improving runtime performance. - -### Display - -Side-by-side displays now uses the same width for the left and right -columns, regardless of the content. - -### Internals - -Difftastic is now a library with a main binary. No APIs are considered -stable for external usage. This is intended to make benchmarking -easier. - -## 0.8 (released 5 September 2021) - -### Git integration - -Fixed a crash on removing whole files. - -### Parsing - -Tree-sitter parsing is now the default, unless the environment -variable DFT_RX is set. - -Tree-sitter parser: Improved handling of string literals. Improved -matching of delimiters. - -Added Python parser. - -Added Java parser. - -JSON (legacy parser): fixed parsing string literals (broken in 0.7). - -Removed Scheme support, as there's no tree-sitter parser available. - -### Display - -Fixed crashes on files with non-ASCII characters on long lines. - -Fixed an issue where multiline comments were not highlighted -correctly. - -Improved display to better use the whole width when whole files are -added or removed. - -### Command Line Interface - -Removed the unused `--lang` argument. - -Difftastic now handles writing to a closed pipe (SIGPIPE) gracefully -rather than crashing. - -Difftastic now has some debugging logs available. `RUST_LOG=trace` -will show information on the route found during graph solving. - -## 0.7 (released 24 August 2021) - -### Git integration - -Fixed issues when adding/removing a whole file meant that difftastic -didn't display anything. - -Fixed a crash on renaming a file. - -Colour is now enabled when using git with a pager. - -### Display - -Side-by-side display now uses "..." for column numbers when aligning -lines. This makes hunks more obvious, but hunks now also have two -blank lines between them to make it clearer. - -Fixed an issue where screen width was not shared evenly by LHS and -RHS. - -Side-by-side display will now use the full width of the screen when -using a pager (i.e. if stdout is a not a TTY). - -Side-by-side display now handles whole file additions better, -preferring a single column display. - -Display width calculations are now based on the longest line visible -in the diff, not the longest line in the file. - -### Parsing - -Added tree-sitter parsers. These have known bugs, but you can try -them by setting the environment variable `DFT_TS=y`. - -Fixed handling of `->` in Rust. - -### Diffing - -Difftastic will now prefer matching up comments that are similar -(according to levenshtein distance). - -Contiguous syntax logic now considers close delimiter positions, so -`[ \n ];` now treats the `;` atom as contiguous. - -Fixed an issue where diffs would prefer prefer a low depth change on a -delimiter over a delimiter that gave contiguous changes. - -### Command Line Interface - -Removed the `--width` argument. - -Added debug options `--dump-syntax` and `--dump-ts` for viewing parse -trees. The output of these options may change without notice. - -## 0.6 (released 27 July 2021) - -### Parsing - -Fixed handling of `@`, `<` and `>` in elisp. - -Fixed crash on binary files. Difftastic now simply shows "binary" for -files that don't look like text. - -Added a basic Go parser. - -### Diffing - -Fixed an issue where comment replacements were not detected. - -Changed words in comments are now only highlighted when comments are -relatively similar (according to their Levenshtein distance). - -Multiline comments are now considered unchanged if only their -indentation changes. - -Improved alignment for lines at the beginning of a changed group of -lines. - -Improved horizontal spacing between before and after code shown. - -Fixed an issue where source code containing tab characters was not -correctly aligned. - -### Command Line Interface - -Removed unused `--inline` and `--context` arguments. - -Fixed crash when called with no arguments. - -## 0.5 (released 22 July 2021) - -### Parsing - -Fixed a crash on parsing non-ASCII source files. Fixed a crash on -files without an extension. Fixed crashes on empty files. - -Input files that aren't valid UTF-8 are now replaced with � rather -than giving up. - -Improved parsing for Rust punctuation. - -Improved parsing for OCaml punctuation, including `:=` and `method!`. - -Improved parsing for Emacs Lisp symbols containing `+` and `=`, and -punctuation of `#`, `.` and `&`. - -Improved parsing for Scheme symbols containing `=`, and punctuation of -`#` and `.`. - -Improved parsing of `=` and `&` in Clojure. - -Improved parsing of `:`, `,`, and constants in JSON. - -Improved parsing of string literals in all languages, supporting -escaped delimiters such as `"\""` and removing incorrect support for -single-quoted strings in JSON. - -### Diffing - -Reduced memory usage when diffing. - -Difftastic now highlights word-level changes between comments. - -Diffing now prefers contiguous nodes even when entering a list, so -`(foo` is considered contiguous. - -Large AST trees with very few common nodes are now considered wholly -novel, rather than trying to match up the few common nodes. This -avoids nonsensical diffs when toplevel function A is completely -replaced with function B and they only have something trivial in -common (e.g. the `function` keyword). - -### Command Line Interface - -Improved `--help`. - -### Integration - -It's now possible to use `difftastic` with `git diff` and `git show`! - -## 0.4 (released 13 July 2021) - -### Parsing - -Improved parsing for Rust macro definitions and punctuation. - -Improved parsing for OCaml punctuation, and added `.mli` as an OCaml -file extension. - -### Diffing - -Diff calculation is now significantly faster. - -Difftastic now considers nesting depth when comparing AST nodes, and -tries to match nodes with similar nesting levels. - -Difftastic now prefers marking multiple items on the same line as -novel, rather than adjacent items on different lines. This helps avoid -[sliders](https://twitter.com/_wilfredh/status/1411949035871637509), -where the diff chooses a keyword on the 'wrong' side. - -Fixed an issue where complex diffs would not display some unchanged -lines. - -### Robustness - -Fixed a crash when diff context included the first line. - -Fixed a crash when plain text content contained certain non-ASCII -characters. - -## 0.3 (released 7 July 2021) - -Diffs are now displayed with unchanged lines aligned to the other side. - -Improved Rust parsing to recognise lifetime syntax `'foo`, character -literals `'x'` and punctuation. - -Improved punctuation parsing for OCaml and JS. - -Fixed an issue where the diff calculated may not be minimal. - -Fixed a crash on files with no changes. - -## 0.2 (released 4 July 2021) - -First version using Dijkstra's algorithm for calculating diffs. - -## 0.1 - -Experimenting with different implementation ideas. +- Structural diffs over Git ranges with `git diff` argument compatibility. +- Streaming NDJSON output (`--format ndjson`, `--stream-annotations`) for + editor and GUI frontends. +- A plugin contract (`wit/plugin.wit`) with bundled plugins for context, + deleted bodies, grouping, hidden files, removed runs, summaries and test + bodies, plus external WASM component plugins. +- A shared configuration file edited through `diffr config`. +- An interactive terminal frontend, `diffr-tui`, derived from hunk. diff --git a/CITATION.cff b/CITATION.cff deleted file mode 100644 index 679daca73..000000000 --- a/CITATION.cff +++ /dev/null @@ -1,15 +0,0 @@ -cff-version: 1.2.0 -title: Difftastic -message: 'To cite difftastic in publications use:' -type: software -authors: - - given-names: Wilfred - family-names: Hughes - email: me@wilfred.me.uk -url: https://github.com/wilfred/difftastic -repository-artifact: https://crates.io/crates/difftastic -abstract: A syntactic diffing tool -keywords: - - diffing - - programming languages -license: MIT diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 000000000..af915bf5d --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,9 @@ +# Contributing + +- Read `AI_POLICY.md` before opening a pull request. +- Run `cargo fmt --all`, `cargo test --locked` and `typos` locally; CI + runs the same. +- Keep pull requests to one change. Describe what changed and why in the + description; the merge squashes it into the history. +- Bug reports use the issue template. Include the diffr version and the + inputs that reproduce the problem. diff --git a/Cargo.lock b/Cargo.lock index e978649b9..e724bddab 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -745,7 +745,7 @@ dependencies = [ [[package]] name = "difftastic" -version = "0.71.0" +version = "0.1.0" dependencies = [ "anyhow", "assert_cmd", diff --git a/Cargo.toml b/Cargo.toml index b1f934be5..98e31213b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "difftastic" -description = "A structural diff that understands syntax." -repository = "https://github.com/wilfred/difftastic" -homepage = "http://difftastic.wilfred.me.uk/" +description = "Structural diffs with a streaming API and interactive terminal frontend." +repository = "https://github.com/devdotfast/diffr" +homepage = "https://github.com/devdotfast/diffr" license = "MIT" -version = "0.71.0" -authors = ["Wilfred Hughes "] +version = "0.1.0" +authors = ["dev.fast"] keywords = ["diff", "syntax"] categories = ["development-tools", "command-line-utilities", "parser-implementations"] edition = "2021" diff --git a/LICENSE b/LICENSE index 80b96e3da..368d86c3e 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,7 @@ MIT License Copyright (c) 2021-2025 Wilfred Hughes +Copyright (c) 2026 dev.fast Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/NOTICE b/NOTICE new file mode 100644 index 000000000..274061975 --- /dev/null +++ b/NOTICE @@ -0,0 +1,25 @@ +diffr is derived from third-party work, each retained under its own license. + +difftastic + https://github.com/Wilfred/difftastic + Copyright (c) 2021-2025 Wilfred Hughes. MIT License (see LICENSE). + diffr forked difftastic at commit 274d0a8f5 (2026-09-08). + +hunk (terminal frontend under tui/) + https://github.com/modem-dev/hunk + Copyright (c) Modem Labs Inc. MIT License (see tui/LICENSE). + Import details in TUI_UPSTREAM.md. + +Helix editor themes (tui/themes/) + https://github.com/helix-editor/helix/tree/master/runtime/themes + Mozilla Public License 2.0 (see tui/themes/LICENSE). + +GitHub Linguist language data (src/tags/linguist/) + https://github.com/github-linguist/linguist + MIT License (see src/tags/linguist/LICENSE). + +tree-sitter grammars (vendored_parsers/) + Each grammar directory carries its upstream license file. Grammars + without a license file in their source tree are listed here: + - tree-sitter-janet-simple: https://github.com/sogaiu/tree-sitter-janet-simple + CC0 1.0 Universal (see vendored_parsers/tree-sitter-janet-simple/LICENSE). diff --git a/README.md b/README.md index 27dbe46f6..77a180029 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,11 @@ # diffr +Structural diffs with a streaming API and an interactive terminal frontend. +diffr is derived from [difftastic](https://github.com/Wilfred/difftastic) +(MIT, Wilfred Hughes) and its terminal UI from +[hunk](https://github.com/modem-dev/hunk) (MIT, Modem Labs). See `NOTICE` +for every upstream and its license. + ## Installation ```sh @@ -129,4 +135,6 @@ or [Writing plugins](docs/plugins.md) for the full guide. ## License -This project was forked from the lovely [difftastic](https://github.com/wilfred/difftastic). +MIT. See `LICENSE` for the terms and `NOTICE` for the third-party work +diffr builds on, starting with the lovely +[difftastic](https://github.com/Wilfred/difftastic). diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 000000000..e3e1180c8 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,7 @@ +# Security + +Report vulnerabilities privately through GitHub's "Report a vulnerability" +button on this repository's Security tab. Do not open a public issue. + +We acknowledge reports within five working days. Fixes ship as a new +release tag; the advisory is published with the release. diff --git a/difft.1 b/difft.1 deleted file mode 100644 index f41e0388a..000000000 --- a/difft.1 +++ /dev/null @@ -1,163 +0,0 @@ -.\" Automatically generated by Pandoc 3.1.13 -.\" -.TH "DIFFT" "1" "" "" "" -.SH NAME -\f[B]difft\f[R] \- a structural diff tool that understands syntax -.SH SYNOPSIS -\f[B]difft\f[R] [\f[I]OPTIONS\f[R]] \f[I]OLD\-PATH\f[R] -\f[I]NEW\-PATH\f[R] -.PP -\f[B]difft\f[R] [\f[I]OPTIONS\f[R]] \f[I]DIRECTORY\-ONE\f[R] -\f[I]DIRECTORY\-TWO\f[R] -.PP -\f[B]difft\f[R] [\f[I]OPTIONS\f[R]] \f[I]FILE\-WITH\-CONFLICTS\f[R] -.PP -\f[B]difft\f[R] \f[B]\-\-list\-languages\f[R] -.PP -\f[B]difft\f[R] \f[B]\-\-help\f[R] -.SH DESCRIPTION -difftastic (difft) is a CLI diff tool that compares files based on their -syntax, not line\-by\-line. -Difftastic produces accurate diffs that are easier for humans to read. -.SS OPTIONS -.TP -\f[B]\-\-background\f[R] \f[I]BACKGROUND\f[R] -Set the background brightness. -Difftastic will prefer brighter colours on dark backgrounds. -.TP -\f[B]\-\-byte\-limit\f[R] \f[I]LIMIT\f[R] -Use a line\-oriented diff if either input file exceeds this size. -.TP -\f[B]\-\-check\-only\f[R] -Report whether there are any changes, but don\[cq]t calculate them. -Much faster. -.TP -\f[B]\-\-color\f[R] \f[I]WHEN\f[R] -When to use color output. -.TP -\f[B]\-\-context\f[R] \f[I]LINES\f[R] -The number of contextual lines to show around changed lines. -.TP -\f[B]\-\-display\f[R] \f[I]MODE\f[R] -Display mode for showing results. -.RS -.PP -\f[I]side\-by\-side\f[R]: Display the before file and the after file in -two separate columns, with line numbers aligned according to unchanged -content. -If a change is exclusively additions or exclusively removals, use a -single column. -.PP -\f[I]side\-by\-side\-show\-both\f[R]: The same as -\f[I]side\-by\-side\f[R], but always uses two columns. -.PP -\f[I]inline\f[R]: A single column display, closer to traditional diff -display. -.PP -\f[I]json\f[R]: Output the results as a machine\-readable JSON array -with an element per file. -.RE -.TP -\f[B]\-\-exit\-code\f[R] -Set the exit code to 1 if there are syntactic changes in any files. -For files where there is no detected language (e.g.\ unsupported -language or binary files), sets the exit code if there are any byte -changes. -.TP -\f[B]\-\-graph\-limit\f[R] \f[I]LIMIT\f[R] -Use a line\-oriented diff if the structural graph exceed this number of -nodes in memory. -.TP -\f[B]\-h, \-\-help\f[R] -Print help information. -.TP -\f[B]\-\-ignore\-comments\f[R] -Don\[cq]t consider comments when diffing. -.TP -\f[B]\-\-list\-languages\f[R] -Print the all the languages supported by difftastic, along with their -extensions. -.TP -\f[B]\-\-override\f[R] \f[I]GLOB:NAME\f[R] -Associate this glob pattern with this language, overriding normal -language detection. -For example: -.RS -.IP -.EX -$ difft \-\-override=\[aq]*.c:C++\[aq] old.c new.c -.EE -.PP -See \f[B]\-\-list\-languages\f[R] for the list of language names. -Language names are matched case insensitively. -Overrides may also specify the language \f[I]\[lq]text\[rq]\f[R] to -treat a file as plain text. -.PP -This argument may be given more than once. -For example: -.IP -.EX -$ difft \-\-override=\[aq]CustomFile:json\[aq] \-\-override=\[aq]*.c:text\[aq] old.c new.c -.EE -.PP -To configure multiple overrides using environment variables, difftastic -also accepts \f[B]DFT_OVERRIDE_1\f[R] up to \f[B]DFT_OVERRIDE_9\f[R]. -.IP -.EX -$ export DFT_OVERRIDE=\[aq]CustomFile:json\[aq] -$ export DFT_OVERRIDE_1=\[aq]*.c:text\[aq] -$ export DFT_OVERRIDE_2=\[aq]*.js:javascript jsx\[aq] -.EE -.PP -When multiple overrides are specified, the first matching override wins. -.RE -.TP -\f[B]\-\-parse\-error\-limit\f[R] \f[I]LIMIT\f[R] -Use a line\-oriented diff if the number of parse errors exceeds this -value. -.TP -\f[B]\-\-skip\-unchanged\f[R] -Don\[cq]t display anything if a file is unchanged. -.TP -\f[B]\-\-sort\-paths\f[R] -When diffing a directory, output the results sorted by path. -This is slower. -.TP -\f[B]\-\-strip\-cr\f[R] -Remove any carriage return characters before diffing. -This can be helpful when dealing with files on Windows that contain -CRLF, i.e.\ \f[CR]\[rs]r\[rs]n\f[R]. -.TP -\f[B]\-\-syntax\-highlight\f[R] \f[I]on/off\f[R] -Enable or disable syntax highlighting. -.TP -\f[B]\-\-tab\-width\f[R] \f[I]NUMSPACES\f[R] -Treat a tab as this many spaces. -.TP -\f[B]\-V, \-\-version\f[R] -Print version information. -.TP -\f[B]\-\-width\f[R] \f[I]COLUMNS\f[R] -Use this many columns when calculating line wrapping. -If not specified, difftastic will detect the terminal width. -.SS DEBUG OPTIONS -.TP -\f[B]\-\-dump\-syntax\f[R] \f[I]PATH\f[R] -Parse a single file with tree\-sitter and display the difftastic syntax -tree. -.TP -\f[B]\-\-dump\-ts\f[R] \f[I]PATH\f[R] -Parse a single file with tree\-sitter and display the tree\-sitter parse -tree. -.SH MANUAL -A full HTML manual is available at \c -.UR https://difftastic.wilfred.me.uk/introduction -.UE \c -\&. -.SH BUGS -See GitHub issues at \c -.UR https://github.com/Wilfred/difftastic/issues -.UE \c -\&. -.SH AUTHOR -Wilfred Hughes me\[at]wilfred.me.uk diff --git a/difft.1.md b/difft.1.md deleted file mode 100644 index 8ce4d6697..000000000 --- a/difft.1.md +++ /dev/null @@ -1,177 +0,0 @@ -% DIFFT(1) - -NAME -==== - -**difft** - a structural diff tool that understands syntax - -SYNOPSIS -======== - -**difft** \[_OPTIONS_] _OLD-PATH_ _NEW-PATH_ - -**difft** \[_OPTIONS_] _DIRECTORY-ONE_ _DIRECTORY-TWO_ - -**difft** \[_OPTIONS_] _FILE-WITH-CONFLICTS_ - -**difft** **\-\-list-languages** - -**difft** **\-\-help** - -DESCRIPTION -=========== - -difftastic (difft) is a CLI diff tool that compares files based on -their syntax, not line-by-line. Difftastic produces accurate diffs -that are easier for humans to read. - -OPTIONS -------- - -**\-\-background** _BACKGROUND_ - -: Set the background brightness. Difftastic will prefer brighter colours on dark - backgrounds. - -**\-\-byte-limit** _LIMIT_ - -: Use a line-oriented diff if either input file exceeds this size. - -**\-\-check-only** - -: Report whether there are any changes, but don't calculate them. Much faster. - -**\-\-color** _WHEN_ - -: When to use color output. - -**\-\-context** _LINES_ - -: The number of contextual lines to show around changed lines. - -**\-\-display** _MODE_ - -: Display mode for showing results. - - _side-by-side_: Display the before file and the after file in two separate columns, with - line numbers aligned according to unchanged content. If a change is exclusively - additions or exclusively removals, use a single column. - - _side-by-side-show-both_: The same as _side-by-side_, but always uses two columns. - - _inline_: A single column display, closer to traditional diff display. - - _json_: Output the results as a machine-readable JSON array with an element per file. - -**\-\-exit-code** - -: Set the exit code to 1 if there are syntactic changes in any files. For files where - there is no detected language (e.g. unsupported language or binary files), sets the exit - code if there are any byte changes. - -**\-\-graph-limit** _LIMIT_ - -: Use a line-oriented diff if the structural graph exceed this number of nodes in memory. - -**-h, \-\-help** - -: Print help information. - -**\-\-ignore-comments** - -: Don't consider comments when diffing. - -**\-\-list-languages** - -: Print the all the languages supported by difftastic, along with their extensions. - -**\-\-override** _GLOB:NAME_ - -: Associate this glob pattern with this language, overriding normal language detection. - For example: - - ``` - $ difft --override='*.c:C++' old.c new.c - ``` - - See **\-\-list-languages** for the list of language names. Language names are matched case - insensitively. Overrides may also specify the language _"text"_ to treat a file as plain - text. - - This argument may be given more than once. For example: - - ``` - $ difft --override='CustomFile:json' --override='*.c:text' old.c new.c - ``` - - To configure multiple overrides using environment variables, difftastic also accepts - **DFT_OVERRIDE_1** up to **DFT_OVERRIDE_9**. - - ``` - $ export DFT_OVERRIDE='CustomFile:json' - $ export DFT_OVERRIDE_1='*.c:text' - $ export DFT_OVERRIDE_2='*.js:javascript jsx' - ``` - - When multiple overrides are specified, the first matching override wins. - -**\-\-parse-error-limit** _LIMIT_ - -: Use a line-oriented diff if the number of parse errors exceeds this value. - -**\-\-skip-unchanged** - -: Don't display anything if a file is unchanged. - -**\-\-sort-paths** - -: When diffing a directory, output the results sorted by path. This is slower. - -**\-\-strip-cr** - -: Remove any carriage return characters before diffing. This can be helpful when dealing - with files on Windows that contain CRLF, i.e. `\r\n`. - -**\-\-syntax-highlight** _on/off_ - -: Enable or disable syntax highlighting. - -**\-\-tab-width** _NUMSPACES_ - -: Treat a tab as this many spaces. - -**-V, \-\-version** - -: Print version information. - -**\-\-width** _COLUMNS_ - -: Use this many columns when calculating line wrapping. If not specified, difftastic will - detect the terminal width. - -DEBUG OPTIONS -------------- - -**\-\-dump-syntax** _PATH_ - -: Parse a single file with tree-sitter and display the difftastic syntax tree. - -**\-\-dump-ts** _PATH_ - -: Parse a single file with tree-sitter and display the tree-sitter parse - tree. - -MANUAL -====== - -A full HTML manual is available at . - -BUGS -==== - -See GitHub issues at . - -AUTHOR -====== - -Wilfred Hughes me@wilfred.me.uk diff --git a/homepage/favicon.ico b/homepage/favicon.ico deleted file mode 100644 index e23527606..000000000 Binary files a/homepage/favicon.ico and /dev/null differ diff --git a/homepage/home_img/add_wrap.png b/homepage/home_img/add_wrap.png deleted file mode 100644 index c0524d01d..000000000 Binary files a/homepage/home_img/add_wrap.png and /dev/null differ diff --git a/homepage/home_img/braces.svg b/homepage/home_img/braces.svg deleted file mode 100644 index a8d55c99a..000000000 --- a/homepage/home_img/braces.svg +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/homepage/home_img/change_wrap.png b/homepage/home_img/change_wrap.png deleted file mode 100644 index 048a7dd74..000000000 Binary files a/homepage/home_img/change_wrap.png and /dev/null differ diff --git a/homepage/home_img/clojure.svg b/homepage/home_img/clojure.svg deleted file mode 100644 index 414825276..000000000 --- a/homepage/home_img/clojure.svg +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/homepage/home_img/cplusplus.svg b/homepage/home_img/cplusplus.svg deleted file mode 100644 index 1480a1529..000000000 --- a/homepage/home_img/cplusplus.svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/homepage/home_img/csharp.svg b/homepage/home_img/csharp.svg deleted file mode 100644 index acc487eb5..000000000 --- a/homepage/home_img/csharp.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/homepage/home_img/dart.svg b/homepage/home_img/dart.svg deleted file mode 100644 index 8c78fdb26..000000000 --- a/homepage/home_img/dart.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/homepage/home_img/difft_screenshot.png b/homepage/home_img/difft_screenshot.png deleted file mode 100644 index 9431d2e3d..000000000 Binary files a/homepage/home_img/difft_screenshot.png and /dev/null differ diff --git a/homepage/home_img/erlang.svg b/homepage/home_img/erlang.svg deleted file mode 100644 index 08909d02e..000000000 --- a/homepage/home_img/erlang.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/homepage/home_img/git_difftool.png b/homepage/home_img/git_difftool.png deleted file mode 100644 index 21fb34fd8..000000000 Binary files a/homepage/home_img/git_difftool.png and /dev/null differ diff --git a/homepage/home_img/github.svg b/homepage/home_img/github.svg deleted file mode 100644 index 013e02532..000000000 --- a/homepage/home_img/github.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/homepage/home_img/go.svg b/homepage/home_img/go.svg deleted file mode 100644 index 0fbf6fd1d..000000000 --- a/homepage/home_img/go.svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/homepage/home_img/haskell.svg b/homepage/home_img/haskell.svg deleted file mode 100644 index d3cc31129..000000000 --- a/homepage/home_img/haskell.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/homepage/home_img/html5.svg b/homepage/home_img/html5.svg deleted file mode 100644 index c2dda3a42..000000000 --- a/homepage/home_img/html5.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/homepage/home_img/java.svg b/homepage/home_img/java.svg deleted file mode 100644 index 051bf254a..000000000 --- a/homepage/home_img/java.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/homepage/home_img/javascript.svg b/homepage/home_img/javascript.svg deleted file mode 100644 index 7975261bd..000000000 --- a/homepage/home_img/javascript.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/homepage/home_img/json.svg b/homepage/home_img/json.svg deleted file mode 100644 index cbbdadf0c..000000000 --- a/homepage/home_img/json.svg +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - - - - - - - diff --git a/homepage/home_img/kotlin.svg b/homepage/home_img/kotlin.svg deleted file mode 100644 index 8646a957d..000000000 --- a/homepage/home_img/kotlin.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/homepage/home_img/line_numbers.png b/homepage/home_img/line_numbers.png deleted file mode 100644 index 8b9a10648..000000000 Binary files a/homepage/home_img/line_numbers.png and /dev/null differ diff --git a/homepage/home_img/lisp.svg b/homepage/home_img/lisp.svg deleted file mode 100644 index fea092711..000000000 --- a/homepage/home_img/lisp.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/homepage/home_img/lua.svg b/homepage/home_img/lua.svg deleted file mode 100644 index 5757ccead..000000000 --- a/homepage/home_img/lua.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/homepage/home_img/ocaml.svg b/homepage/home_img/ocaml.svg deleted file mode 100644 index 42033d978..000000000 --- a/homepage/home_img/ocaml.svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/homepage/home_img/php.svg b/homepage/home_img/php.svg deleted file mode 100644 index 0212714ff..000000000 --- a/homepage/home_img/php.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/homepage/home_img/python.svg b/homepage/home_img/python.svg deleted file mode 100644 index d087cccf6..000000000 --- a/homepage/home_img/python.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/homepage/home_img/r.svg b/homepage/home_img/r.svg deleted file mode 100644 index 7c68a98d8..000000000 --- a/homepage/home_img/r.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/homepage/home_img/reformat.png b/homepage/home_img/reformat.png deleted file mode 100644 index 097586bb3..000000000 Binary files a/homepage/home_img/reformat.png and /dev/null differ diff --git a/homepage/home_img/ruby.svg b/homepage/home_img/ruby.svg deleted file mode 100644 index 9c651106b..000000000 --- a/homepage/home_img/ruby.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/homepage/home_img/rust.svg b/homepage/home_img/rust.svg deleted file mode 100644 index a1fe0d869..000000000 --- a/homepage/home_img/rust.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/homepage/home_img/scala.svg b/homepage/home_img/scala.svg deleted file mode 100644 index 6d3fd54a0..000000000 --- a/homepage/home_img/scala.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/homepage/home_img/typescript.svg b/homepage/home_img/typescript.svg deleted file mode 100644 index e1db5f196..000000000 --- a/homepage/home_img/typescript.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/homepage/home_img/wrap_struct.png b/homepage/home_img/wrap_struct.png deleted file mode 100644 index a824feff9..000000000 Binary files a/homepage/home_img/wrap_struct.png and /dev/null differ diff --git a/homepage/home_img/yaml.svg b/homepage/home_img/yaml.svg deleted file mode 100644 index ca064aa0e..000000000 --- a/homepage/home_img/yaml.svg +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/homepage/home_static/asciinema-player.css b/homepage/home_static/asciinema-player.css deleted file mode 100644 index e7b48cb49..000000000 --- a/homepage/home_static/asciinema-player.css +++ /dev/null @@ -1,2835 +0,0 @@ -div.ap-wrapper { - outline: none; - height: 100%; - display: flex; - justify-content: center; -} -div.ap-wrapper .title-bar { - display: none; - top: -78px; - transition: top 0.15s linear; - position: absolute; - left: 0; - right: 0; - box-sizing: content-box; - font-size: 20px; - line-height: 1em; - padding: 15px; - font-family: sans-serif; - color: white; - background-color: rgba(0, 0, 0, 0.8); -} -div.ap-wrapper .title-bar img { - vertical-align: middle; - height: 48px; - margin-right: 16px; -} -div.ap-wrapper .title-bar a { - color: white; - text-decoration: underline; -} -div.ap-wrapper .title-bar a:hover { - text-decoration: none; -} -div.ap-wrapper:fullscreen { - background-color: #000; - width: 100%; - align-items: center; -} -div.ap-wrapper:fullscreen div.ap-player { - position: static; -} -div.ap-wrapper:fullscreen .title-bar { - display: initial; -} -div.ap-wrapper:fullscreen.hud .title-bar { - top: 0; -} -div.ap-wrapper div.ap-player { - text-align: left; - display: inline-block; - padding: 0px; - position: relative; - box-sizing: content-box; - overflow: hidden; - max-width: 100%; - border-radius: 4px; - font-size: 15px; -} -pre.ap-terminal { - box-sizing: content-box; - overflow: hidden; - padding: 0; - margin: 0px; - display: block; - white-space: pre; - word-wrap: normal; - word-break: normal; - border-radius: 0; - border-style: solid; - cursor: text; - border-width: 0.75em; - font-family: Consolas, Menlo, 'Bitstream Vera Sans Mono', monospace, 'Powerline Symbols'; - font-variant-ligatures: none; -} -pre.ap-terminal .ap-line { - letter-spacing: normal; - overflow: hidden; -} -pre.ap-terminal .ap-line span { - padding: 0; - display: inline-block; - height: 100%; -} -pre.ap-terminal .ap-line { - display: block; - width: 200%; -} -pre.ap-terminal .ap-line .ap-cursor-a { - display: inline-block; -} -pre.ap-terminal .ap-line .ap-cursor-b { - display: none; - border-radius: 0.05em; -} -pre.ap-terminal .ap-line .ap-blink { - visibility: hidden; -} -pre.ap-terminal.ap-cursor .ap-line .ap-cursor-a { - display: none; -} -pre.ap-terminal.ap-cursor .ap-line .ap-cursor-b { - display: inline-block; -} -pre.ap-terminal.ap-blink .ap-line .ap-blink { - visibility: visible; -} -pre.ap-terminal .ap-bright { - font-weight: bold; -} -pre.ap-terminal .ap-faint { - opacity: 0.5; -} -pre.ap-terminal .ap-underline { - text-decoration: underline; -} -pre.ap-terminal .ap-italic { - font-style: italic; -} -pre.ap-terminal .ap-strikethrough { - text-decoration: line-through; -} -div.ap-player div.ap-control-bar { - width: 100%; - height: 32px; - display: flex; - justify-content: space-between; - align-items: stretch; - background: linear-gradient(to bottom, rgba(0, 0, 0, 0.5) 0%, #000000 25%, #000000 100%); - color: #bbb; - box-sizing: content-box; - line-height: 1; - position: absolute; - bottom: 0; - left: 0; - opacity: 0; - transition: opacity 0.15s linear; - user-select: none; - z-index: 30; -} -div.ap-player div.ap-control-bar * { - box-sizing: inherit; - font-size: 0; - font-family: Helvetica, Arial, sans-serif; - font-weight: bold; -} -div.ap-control-bar svg.ap-icon path { - fill: #bbb; -} -div.ap-control-bar span.ap-playback-button { - display: block; - flex: 0 0 auto; - cursor: pointer; - height: 12px; - width: 12px; - padding: 10px; -} -div.ap-control-bar span.ap-playback-button svg { - height: 12px; - width: 12px; -} -div.ap-control-bar span.ap-timer { - display: block; - flex: 0 0 auto; - min-width: 50px; - margin: 0 10px; - height: 100%; - text-align: center; - font-size: 11px; - line-height: 34px; - cursor: default; -} -div.ap-control-bar span.ap-timer span { - display: inline-block; - font-size: inherit; -} -div.ap-control-bar span.ap-timer .ap-time-remaining { - display: none; -} -div.ap-control-bar span.ap-timer:hover .ap-time-elapsed { - display: none; -} -div.ap-control-bar span.ap-timer:hover .ap-time-remaining { - display: inline; -} -div.ap-control-bar .ap-progressbar { - display: block; - flex: 1 1 auto; - height: 100%; - padding: 0 10px; -} -div.ap-control-bar .ap-progressbar .ap-bar { - display: block; - position: relative; - cursor: default; - height: 100%; - font-size: 0; -} -div.ap-control-bar .ap-progressbar .ap-bar .ap-gutter { - display: block; - position: absolute; - top: 15px; - left: 0; - right: 0; - height: 3px; - background-color: #333; -} -div.ap-control-bar .ap-progressbar .ap-bar .ap-gutter .ap-gutter-fill { - display: inline-block; - height: 100%; - background-color: #bbb; - border-radius: 3px; - z-index: 10; -} -div.ap-control-bar.ap-seekable .ap-progressbar .ap-bar { - cursor: pointer; -} -div.ap-control-bar .ap-fullscreen-button { - display: block; - flex: 0 0 auto; - width: 14px; - height: 14px; - padding: 9px; - cursor: pointer; -} -div.ap-control-bar .ap-fullscreen-button svg { - width: 14px; - height: 14px; -} -div.ap-control-bar .ap-fullscreen-button svg:first-child { - display: inline; -} -div.ap-control-bar .ap-fullscreen-button svg:last-child { - display: none; -} -div.ap-wrapper.ap-hud .ap-control-bar { - opacity: 1; -} -div.ap-wrapper:fullscreen .ap-fullscreen-button svg:first-child { - display: none; -} -div.ap-wrapper:fullscreen .ap-fullscreen-button svg:last-child { - display: inline; -} -span.ap-progressbar span.ap-marker-container { - display: block; - top: 0; - bottom: 0; - width: 21px; - position: absolute; - margin-left: -10px; - z-index: 9; -} -span.ap-marker-container span.ap-marker { - display: block; - top: 13px; - bottom: 12px; - left: 7px; - right: 7px; - background-color: #555; - position: absolute; - transition: top 0.1s, bottom 0.1s, left 0.1s, right 0.1s, background-color 0.1s; - border-radius: 50%; -} -span.ap-marker-container span.ap-marker.ap-marker-past { - background-color: #bbb; -} -span.ap-marker-container span.ap-marker:hover, -span.ap-marker-container:hover span.ap-marker { - background-color: #bbb; - top: 11px; - bottom: 10px; - left: 5px; - right: 5px; -} -span.ap-marker-container span.ap-marker-tooltip { - visibility: hidden; - background-color: #333; - color: #bbb; - text-align: center; - padding: 2px 8px 0px 8px; - border-radius: 4px; - position: absolute; - z-index: 1; - white-space: nowrap; - /* Prevents the text from wrapping and makes sure the tooltip width adapts to the text length */ - font-size: 11px; - line-height: 2em; - bottom: 100%; - left: 50%; - transform: translateX(-50%); -} -span.ap-marker-container:hover span.ap-marker-tooltip { - visibility: visible; -} -.ap-player .ap-overlay { - z-index: 10; - background-repeat: no-repeat; - background-position: center; - position: absolute; - top: 0; - left: 0; - right: 0; - bottom: 0; - display: flex; - justify-content: center; - align-items: center; -} -.ap-player .ap-overlay-start { - cursor: pointer; -} -.ap-player .ap-overlay-start .ap-play-button { - font-size: 0px; - position: absolute; - left: 0; - top: 0; - right: 0; - bottom: 0; - text-align: center; - color: white; - height: 80px; - max-height: 66%; - margin: auto; -} -.ap-player .ap-overlay-start .ap-play-button div { - height: 100%; -} -.ap-player .ap-overlay-start .ap-play-button div span { - height: 100%; - display: block; -} -.ap-player .ap-overlay-start .ap-play-button div span svg { - height: 100%; -} -.ap-player .ap-overlay-loading .ap-loader { - width: 48px; - height: 48px; - border-radius: 50%; - display: inline-block; - position: relative; - border: 10px solid; - border-color: rgba(255, 255, 255, 0.15) rgba(255, 255, 255, 0.25) rgba(255, 255, 255, 0.35) rgba(255, 255, 255, 0.5); - box-sizing: border-box; - animation: ap-loader-rotation 1s linear infinite; -} -.ap-player .ap-overlay-offline span { - font-family: Consolas, Menlo, 'Bitstream Vera Sans Mono', monospace, 'Powerline Symbols'; - font-variant-ligatures: none; - font-size: 2em; -} -.ap-player .ap-overlay-offline span .ap-line { - letter-spacing: normal; - overflow: hidden; -} -.ap-player .ap-overlay-offline span .ap-line span { - padding: 0; - display: inline-block; - height: 100%; -} -.ap-player .ap-overlay-error span { - font-size: 8em; -} -@keyframes ap-loader-rotation { - 0% { - transform: rotate(0deg); - } - 100% { - transform: rotate(360deg); - } -} -.ap-terminal .fg-16 { - color: #000000; -} -.ap-terminal .bg-16 { - background-color: #000000; -} -.ap-terminal .fg-17 { - color: #00005f; -} -.ap-terminal .bg-17 { - background-color: #00005f; -} -.ap-terminal .fg-18 { - color: #000087; -} -.ap-terminal .bg-18 { - background-color: #000087; -} -.ap-terminal .fg-19 { - color: #0000af; -} -.ap-terminal .bg-19 { - background-color: #0000af; -} -.ap-terminal .fg-20 { - color: #0000d7; -} -.ap-terminal .bg-20 { - background-color: #0000d7; -} -.ap-terminal .fg-21 { - color: #0000ff; -} -.ap-terminal .bg-21 { - background-color: #0000ff; -} -.ap-terminal .fg-22 { - color: #005f00; -} -.ap-terminal .bg-22 { - background-color: #005f00; -} -.ap-terminal .fg-23 { - color: #005f5f; -} -.ap-terminal .bg-23 { - background-color: #005f5f; -} -.ap-terminal .fg-24 { - color: #005f87; -} -.ap-terminal .bg-24 { - background-color: #005f87; -} -.ap-terminal .fg-25 { - color: #005faf; -} -.ap-terminal .bg-25 { - background-color: #005faf; -} -.ap-terminal .fg-26 { - color: #005fd7; -} -.ap-terminal .bg-26 { - background-color: #005fd7; -} -.ap-terminal .fg-27 { - color: #005fff; -} -.ap-terminal .bg-27 { - background-color: #005fff; -} -.ap-terminal .fg-28 { - color: #008700; -} -.ap-terminal .bg-28 { - background-color: #008700; -} -.ap-terminal .fg-29 { - color: #00875f; -} -.ap-terminal .bg-29 { - background-color: #00875f; -} -.ap-terminal .fg-30 { - color: #008787; -} -.ap-terminal .bg-30 { - background-color: #008787; -} -.ap-terminal .fg-31 { - color: #0087af; -} -.ap-terminal .bg-31 { - background-color: #0087af; -} -.ap-terminal .fg-32 { - color: #0087d7; -} -.ap-terminal .bg-32 { - background-color: #0087d7; -} -.ap-terminal .fg-33 { - color: #0087ff; -} -.ap-terminal .bg-33 { - background-color: #0087ff; -} -.ap-terminal .fg-34 { - color: #00af00; -} -.ap-terminal .bg-34 { - background-color: #00af00; -} -.ap-terminal .fg-35 { - color: #00af5f; -} -.ap-terminal .bg-35 { - background-color: #00af5f; -} -.ap-terminal .fg-36 { - color: #00af87; -} -.ap-terminal .bg-36 { - background-color: #00af87; -} -.ap-terminal .fg-37 { - color: #00afaf; -} -.ap-terminal .bg-37 { - background-color: #00afaf; -} -.ap-terminal .fg-38 { - color: #00afd7; -} -.ap-terminal .bg-38 { - background-color: #00afd7; -} -.ap-terminal .fg-39 { - color: #00afff; -} -.ap-terminal .bg-39 { - background-color: #00afff; -} -.ap-terminal .fg-40 { - color: #00d700; -} -.ap-terminal .bg-40 { - background-color: #00d700; -} -.ap-terminal .fg-41 { - color: #00d75f; -} -.ap-terminal .bg-41 { - background-color: #00d75f; -} -.ap-terminal .fg-42 { - color: #00d787; -} -.ap-terminal .bg-42 { - background-color: #00d787; -} -.ap-terminal .fg-43 { - color: #00d7af; -} -.ap-terminal .bg-43 { - background-color: #00d7af; -} -.ap-terminal .fg-44 { - color: #00d7d7; -} -.ap-terminal .bg-44 { - background-color: #00d7d7; -} -.ap-terminal .fg-45 { - color: #00d7ff; -} -.ap-terminal .bg-45 { - background-color: #00d7ff; -} -.ap-terminal .fg-46 { - color: #00ff00; -} -.ap-terminal .bg-46 { - background-color: #00ff00; -} -.ap-terminal .fg-47 { - color: #00ff5f; -} -.ap-terminal .bg-47 { - background-color: #00ff5f; -} -.ap-terminal .fg-48 { - color: #00ff87; -} -.ap-terminal .bg-48 { - background-color: #00ff87; -} -.ap-terminal .fg-49 { - color: #00ffaf; -} -.ap-terminal .bg-49 { - background-color: #00ffaf; -} -.ap-terminal .fg-50 { - color: #00ffd7; -} -.ap-terminal .bg-50 { - background-color: #00ffd7; -} -.ap-terminal .fg-51 { - color: #00ffff; -} -.ap-terminal .bg-51 { - background-color: #00ffff; -} -.ap-terminal .fg-52 { - color: #5f0000; -} -.ap-terminal .bg-52 { - background-color: #5f0000; -} -.ap-terminal .fg-53 { - color: #5f005f; -} -.ap-terminal .bg-53 { - background-color: #5f005f; -} -.ap-terminal .fg-54 { - color: #5f0087; -} -.ap-terminal .bg-54 { - background-color: #5f0087; -} -.ap-terminal .fg-55 { - color: #5f00af; -} -.ap-terminal .bg-55 { - background-color: #5f00af; -} -.ap-terminal .fg-56 { - color: #5f00d7; -} -.ap-terminal .bg-56 { - background-color: #5f00d7; -} -.ap-terminal .fg-57 { - color: #5f00ff; -} -.ap-terminal .bg-57 { - background-color: #5f00ff; -} -.ap-terminal .fg-58 { - color: #5f5f00; -} -.ap-terminal .bg-58 { - background-color: #5f5f00; -} -.ap-terminal .fg-59 { - color: #5f5f5f; -} -.ap-terminal .bg-59 { - background-color: #5f5f5f; -} -.ap-terminal .fg-60 { - color: #5f5f87; -} -.ap-terminal .bg-60 { - background-color: #5f5f87; -} -.ap-terminal .fg-61 { - color: #5f5faf; -} -.ap-terminal .bg-61 { - background-color: #5f5faf; -} -.ap-terminal .fg-62 { - color: #5f5fd7; -} -.ap-terminal .bg-62 { - background-color: #5f5fd7; -} -.ap-terminal .fg-63 { - color: #5f5fff; -} -.ap-terminal .bg-63 { - background-color: #5f5fff; -} -.ap-terminal .fg-64 { - color: #5f8700; -} -.ap-terminal .bg-64 { - background-color: #5f8700; -} -.ap-terminal .fg-65 { - color: #5f875f; -} -.ap-terminal .bg-65 { - background-color: #5f875f; -} -.ap-terminal .fg-66 { - color: #5f8787; -} -.ap-terminal .bg-66 { - background-color: #5f8787; -} -.ap-terminal .fg-67 { - color: #5f87af; -} -.ap-terminal .bg-67 { - background-color: #5f87af; -} -.ap-terminal .fg-68 { - color: #5f87d7; -} -.ap-terminal .bg-68 { - background-color: #5f87d7; -} -.ap-terminal .fg-69 { - color: #5f87ff; -} -.ap-terminal .bg-69 { - background-color: #5f87ff; -} -.ap-terminal .fg-70 { - color: #5faf00; -} -.ap-terminal .bg-70 { - background-color: #5faf00; -} -.ap-terminal .fg-71 { - color: #5faf5f; -} -.ap-terminal .bg-71 { - background-color: #5faf5f; -} -.ap-terminal .fg-72 { - color: #5faf87; -} -.ap-terminal .bg-72 { - background-color: #5faf87; -} -.ap-terminal .fg-73 { - color: #5fafaf; -} -.ap-terminal .bg-73 { - background-color: #5fafaf; -} -.ap-terminal .fg-74 { - color: #5fafd7; -} -.ap-terminal .bg-74 { - background-color: #5fafd7; -} -.ap-terminal .fg-75 { - color: #5fafff; -} -.ap-terminal .bg-75 { - background-color: #5fafff; -} -.ap-terminal .fg-76 { - color: #5fd700; -} -.ap-terminal .bg-76 { - background-color: #5fd700; -} -.ap-terminal .fg-77 { - color: #5fd75f; -} -.ap-terminal .bg-77 { - background-color: #5fd75f; -} -.ap-terminal .fg-78 { - color: #5fd787; -} -.ap-terminal .bg-78 { - background-color: #5fd787; -} -.ap-terminal .fg-79 { - color: #5fd7af; -} -.ap-terminal .bg-79 { - background-color: #5fd7af; -} -.ap-terminal .fg-80 { - color: #5fd7d7; -} -.ap-terminal .bg-80 { - background-color: #5fd7d7; -} -.ap-terminal .fg-81 { - color: #5fd7ff; -} -.ap-terminal .bg-81 { - background-color: #5fd7ff; -} -.ap-terminal .fg-82 { - color: #5fff00; -} -.ap-terminal .bg-82 { - background-color: #5fff00; -} -.ap-terminal .fg-83 { - color: #5fff5f; -} -.ap-terminal .bg-83 { - background-color: #5fff5f; -} -.ap-terminal .fg-84 { - color: #5fff87; -} -.ap-terminal .bg-84 { - background-color: #5fff87; -} -.ap-terminal .fg-85 { - color: #5fffaf; -} -.ap-terminal .bg-85 { - background-color: #5fffaf; -} -.ap-terminal .fg-86 { - color: #5fffd7; -} -.ap-terminal .bg-86 { - background-color: #5fffd7; -} -.ap-terminal .fg-87 { - color: #5fffff; -} -.ap-terminal .bg-87 { - background-color: #5fffff; -} -.ap-terminal .fg-88 { - color: #870000; -} -.ap-terminal .bg-88 { - background-color: #870000; -} -.ap-terminal .fg-89 { - color: #87005f; -} -.ap-terminal .bg-89 { - background-color: #87005f; -} -.ap-terminal .fg-90 { - color: #870087; -} -.ap-terminal .bg-90 { - background-color: #870087; -} -.ap-terminal .fg-91 { - color: #8700af; -} -.ap-terminal .bg-91 { - background-color: #8700af; -} -.ap-terminal .fg-92 { - color: #8700d7; -} -.ap-terminal .bg-92 { - background-color: #8700d7; -} -.ap-terminal .fg-93 { - color: #8700ff; -} -.ap-terminal .bg-93 { - background-color: #8700ff; -} -.ap-terminal .fg-94 { - color: #875f00; -} -.ap-terminal .bg-94 { - background-color: #875f00; -} -.ap-terminal .fg-95 { - color: #875f5f; -} -.ap-terminal .bg-95 { - background-color: #875f5f; -} -.ap-terminal .fg-96 { - color: #875f87; -} -.ap-terminal .bg-96 { - background-color: #875f87; -} -.ap-terminal .fg-97 { - color: #875faf; -} -.ap-terminal .bg-97 { - background-color: #875faf; -} -.ap-terminal .fg-98 { - color: #875fd7; -} -.ap-terminal .bg-98 { - background-color: #875fd7; -} -.ap-terminal .fg-99 { - color: #875fff; -} -.ap-terminal .bg-99 { - background-color: #875fff; -} -.ap-terminal .fg-100 { - color: #878700; -} -.ap-terminal .bg-100 { - background-color: #878700; -} -.ap-terminal .fg-101 { - color: #87875f; -} -.ap-terminal .bg-101 { - background-color: #87875f; -} -.ap-terminal .fg-102 { - color: #878787; -} -.ap-terminal .bg-102 { - background-color: #878787; -} -.ap-terminal .fg-103 { - color: #8787af; -} -.ap-terminal .bg-103 { - background-color: #8787af; -} -.ap-terminal .fg-104 { - color: #8787d7; -} -.ap-terminal .bg-104 { - background-color: #8787d7; -} -.ap-terminal .fg-105 { - color: #8787ff; -} -.ap-terminal .bg-105 { - background-color: #8787ff; -} -.ap-terminal .fg-106 { - color: #87af00; -} -.ap-terminal .bg-106 { - background-color: #87af00; -} -.ap-terminal .fg-107 { - color: #87af5f; -} -.ap-terminal .bg-107 { - background-color: #87af5f; -} -.ap-terminal .fg-108 { - color: #87af87; -} -.ap-terminal .bg-108 { - background-color: #87af87; -} -.ap-terminal .fg-109 { - color: #87afaf; -} -.ap-terminal .bg-109 { - background-color: #87afaf; -} -.ap-terminal .fg-110 { - color: #87afd7; -} -.ap-terminal .bg-110 { - background-color: #87afd7; -} -.ap-terminal .fg-111 { - color: #87afff; -} -.ap-terminal .bg-111 { - background-color: #87afff; -} -.ap-terminal .fg-112 { - color: #87d700; -} -.ap-terminal .bg-112 { - background-color: #87d700; -} -.ap-terminal .fg-113 { - color: #87d75f; -} -.ap-terminal .bg-113 { - background-color: #87d75f; -} -.ap-terminal .fg-114 { - color: #87d787; -} -.ap-terminal .bg-114 { - background-color: #87d787; -} -.ap-terminal .fg-115 { - color: #87d7af; -} -.ap-terminal .bg-115 { - background-color: #87d7af; -} -.ap-terminal .fg-116 { - color: #87d7d7; -} -.ap-terminal .bg-116 { - background-color: #87d7d7; -} -.ap-terminal .fg-117 { - color: #87d7ff; -} -.ap-terminal .bg-117 { - background-color: #87d7ff; -} -.ap-terminal .fg-118 { - color: #87ff00; -} -.ap-terminal .bg-118 { - background-color: #87ff00; -} -.ap-terminal .fg-119 { - color: #87ff5f; -} -.ap-terminal .bg-119 { - background-color: #87ff5f; -} -.ap-terminal .fg-120 { - color: #87ff87; -} -.ap-terminal .bg-120 { - background-color: #87ff87; -} -.ap-terminal .fg-121 { - color: #87ffaf; -} -.ap-terminal .bg-121 { - background-color: #87ffaf; -} -.ap-terminal .fg-122 { - color: #87ffd7; -} -.ap-terminal .bg-122 { - background-color: #87ffd7; -} -.ap-terminal .fg-123 { - color: #87ffff; -} -.ap-terminal .bg-123 { - background-color: #87ffff; -} -.ap-terminal .fg-124 { - color: #af0000; -} -.ap-terminal .bg-124 { - background-color: #af0000; -} -.ap-terminal .fg-125 { - color: #af005f; -} -.ap-terminal .bg-125 { - background-color: #af005f; -} -.ap-terminal .fg-126 { - color: #af0087; -} -.ap-terminal .bg-126 { - background-color: #af0087; -} -.ap-terminal .fg-127 { - color: #af00af; -} -.ap-terminal .bg-127 { - background-color: #af00af; -} -.ap-terminal .fg-128 { - color: #af00d7; -} -.ap-terminal .bg-128 { - background-color: #af00d7; -} -.ap-terminal .fg-129 { - color: #af00ff; -} -.ap-terminal .bg-129 { - background-color: #af00ff; -} -.ap-terminal .fg-130 { - color: #af5f00; -} -.ap-terminal .bg-130 { - background-color: #af5f00; -} -.ap-terminal .fg-131 { - color: #af5f5f; -} -.ap-terminal .bg-131 { - background-color: #af5f5f; -} -.ap-terminal .fg-132 { - color: #af5f87; -} -.ap-terminal .bg-132 { - background-color: #af5f87; -} -.ap-terminal .fg-133 { - color: #af5faf; -} -.ap-terminal .bg-133 { - background-color: #af5faf; -} -.ap-terminal .fg-134 { - color: #af5fd7; -} -.ap-terminal .bg-134 { - background-color: #af5fd7; -} -.ap-terminal .fg-135 { - color: #af5fff; -} -.ap-terminal .bg-135 { - background-color: #af5fff; -} -.ap-terminal .fg-136 { - color: #af8700; -} -.ap-terminal .bg-136 { - background-color: #af8700; -} -.ap-terminal .fg-137 { - color: #af875f; -} -.ap-terminal .bg-137 { - background-color: #af875f; -} -.ap-terminal .fg-138 { - color: #af8787; -} -.ap-terminal .bg-138 { - background-color: #af8787; -} -.ap-terminal .fg-139 { - color: #af87af; -} -.ap-terminal .bg-139 { - background-color: #af87af; -} -.ap-terminal .fg-140 { - color: #af87d7; -} -.ap-terminal .bg-140 { - background-color: #af87d7; -} -.ap-terminal .fg-141 { - color: #af87ff; -} -.ap-terminal .bg-141 { - background-color: #af87ff; -} -.ap-terminal .fg-142 { - color: #afaf00; -} -.ap-terminal .bg-142 { - background-color: #afaf00; -} -.ap-terminal .fg-143 { - color: #afaf5f; -} -.ap-terminal .bg-143 { - background-color: #afaf5f; -} -.ap-terminal .fg-144 { - color: #afaf87; -} -.ap-terminal .bg-144 { - background-color: #afaf87; -} -.ap-terminal .fg-145 { - color: #afafaf; -} -.ap-terminal .bg-145 { - background-color: #afafaf; -} -.ap-terminal .fg-146 { - color: #afafd7; -} -.ap-terminal .bg-146 { - background-color: #afafd7; -} -.ap-terminal .fg-147 { - color: #afafff; -} -.ap-terminal .bg-147 { - background-color: #afafff; -} -.ap-terminal .fg-148 { - color: #afd700; -} -.ap-terminal .bg-148 { - background-color: #afd700; -} -.ap-terminal .fg-149 { - color: #afd75f; -} -.ap-terminal .bg-149 { - background-color: #afd75f; -} -.ap-terminal .fg-150 { - color: #afd787; -} -.ap-terminal .bg-150 { - background-color: #afd787; -} -.ap-terminal .fg-151 { - color: #afd7af; -} -.ap-terminal .bg-151 { - background-color: #afd7af; -} -.ap-terminal .fg-152 { - color: #afd7d7; -} -.ap-terminal .bg-152 { - background-color: #afd7d7; -} -.ap-terminal .fg-153 { - color: #afd7ff; -} -.ap-terminal .bg-153 { - background-color: #afd7ff; -} -.ap-terminal .fg-154 { - color: #afff00; -} -.ap-terminal .bg-154 { - background-color: #afff00; -} -.ap-terminal .fg-155 { - color: #afff5f; -} -.ap-terminal .bg-155 { - background-color: #afff5f; -} -.ap-terminal .fg-156 { - color: #afff87; -} -.ap-terminal .bg-156 { - background-color: #afff87; -} -.ap-terminal .fg-157 { - color: #afffaf; -} -.ap-terminal .bg-157 { - background-color: #afffaf; -} -.ap-terminal .fg-158 { - color: #afffd7; -} -.ap-terminal .bg-158 { - background-color: #afffd7; -} -.ap-terminal .fg-159 { - color: #afffff; -} -.ap-terminal .bg-159 { - background-color: #afffff; -} -.ap-terminal .fg-160 { - color: #d70000; -} -.ap-terminal .bg-160 { - background-color: #d70000; -} -.ap-terminal .fg-161 { - color: #d7005f; -} -.ap-terminal .bg-161 { - background-color: #d7005f; -} -.ap-terminal .fg-162 { - color: #d70087; -} -.ap-terminal .bg-162 { - background-color: #d70087; -} -.ap-terminal .fg-163 { - color: #d700af; -} -.ap-terminal .bg-163 { - background-color: #d700af; -} -.ap-terminal .fg-164 { - color: #d700d7; -} -.ap-terminal .bg-164 { - background-color: #d700d7; -} -.ap-terminal .fg-165 { - color: #d700ff; -} -.ap-terminal .bg-165 { - background-color: #d700ff; -} -.ap-terminal .fg-166 { - color: #d75f00; -} -.ap-terminal .bg-166 { - background-color: #d75f00; -} -.ap-terminal .fg-167 { - color: #d75f5f; -} -.ap-terminal .bg-167 { - background-color: #d75f5f; -} -.ap-terminal .fg-168 { - color: #d75f87; -} -.ap-terminal .bg-168 { - background-color: #d75f87; -} -.ap-terminal .fg-169 { - color: #d75faf; -} -.ap-terminal .bg-169 { - background-color: #d75faf; -} -.ap-terminal .fg-170 { - color: #d75fd7; -} -.ap-terminal .bg-170 { - background-color: #d75fd7; -} -.ap-terminal .fg-171 { - color: #d75fff; -} -.ap-terminal .bg-171 { - background-color: #d75fff; -} -.ap-terminal .fg-172 { - color: #d78700; -} -.ap-terminal .bg-172 { - background-color: #d78700; -} -.ap-terminal .fg-173 { - color: #d7875f; -} -.ap-terminal .bg-173 { - background-color: #d7875f; -} -.ap-terminal .fg-174 { - color: #d78787; -} -.ap-terminal .bg-174 { - background-color: #d78787; -} -.ap-terminal .fg-175 { - color: #d787af; -} -.ap-terminal .bg-175 { - background-color: #d787af; -} -.ap-terminal .fg-176 { - color: #d787d7; -} -.ap-terminal .bg-176 { - background-color: #d787d7; -} -.ap-terminal .fg-177 { - color: #d787ff; -} -.ap-terminal .bg-177 { - background-color: #d787ff; -} -.ap-terminal .fg-178 { - color: #d7af00; -} -.ap-terminal .bg-178 { - background-color: #d7af00; -} -.ap-terminal .fg-179 { - color: #d7af5f; -} -.ap-terminal .bg-179 { - background-color: #d7af5f; -} -.ap-terminal .fg-180 { - color: #d7af87; -} -.ap-terminal .bg-180 { - background-color: #d7af87; -} -.ap-terminal .fg-181 { - color: #d7afaf; -} -.ap-terminal .bg-181 { - background-color: #d7afaf; -} -.ap-terminal .fg-182 { - color: #d7afd7; -} -.ap-terminal .bg-182 { - background-color: #d7afd7; -} -.ap-terminal .fg-183 { - color: #d7afff; -} -.ap-terminal .bg-183 { - background-color: #d7afff; -} -.ap-terminal .fg-184 { - color: #d7d700; -} -.ap-terminal .bg-184 { - background-color: #d7d700; -} -.ap-terminal .fg-185 { - color: #d7d75f; -} -.ap-terminal .bg-185 { - background-color: #d7d75f; -} -.ap-terminal .fg-186 { - color: #d7d787; -} -.ap-terminal .bg-186 { - background-color: #d7d787; -} -.ap-terminal .fg-187 { - color: #d7d7af; -} -.ap-terminal .bg-187 { - background-color: #d7d7af; -} -.ap-terminal .fg-188 { - color: #d7d7d7; -} -.ap-terminal .bg-188 { - background-color: #d7d7d7; -} -.ap-terminal .fg-189 { - color: #d7d7ff; -} -.ap-terminal .bg-189 { - background-color: #d7d7ff; -} -.ap-terminal .fg-190 { - color: #d7ff00; -} -.ap-terminal .bg-190 { - background-color: #d7ff00; -} -.ap-terminal .fg-191 { - color: #d7ff5f; -} -.ap-terminal .bg-191 { - background-color: #d7ff5f; -} -.ap-terminal .fg-192 { - color: #d7ff87; -} -.ap-terminal .bg-192 { - background-color: #d7ff87; -} -.ap-terminal .fg-193 { - color: #d7ffaf; -} -.ap-terminal .bg-193 { - background-color: #d7ffaf; -} -.ap-terminal .fg-194 { - color: #d7ffd7; -} -.ap-terminal .bg-194 { - background-color: #d7ffd7; -} -.ap-terminal .fg-195 { - color: #d7ffff; -} -.ap-terminal .bg-195 { - background-color: #d7ffff; -} -.ap-terminal .fg-196 { - color: #ff0000; -} -.ap-terminal .bg-196 { - background-color: #ff0000; -} -.ap-terminal .fg-197 { - color: #ff005f; -} -.ap-terminal .bg-197 { - background-color: #ff005f; -} -.ap-terminal .fg-198 { - color: #ff0087; -} -.ap-terminal .bg-198 { - background-color: #ff0087; -} -.ap-terminal .fg-199 { - color: #ff00af; -} -.ap-terminal .bg-199 { - background-color: #ff00af; -} -.ap-terminal .fg-200 { - color: #ff00d7; -} -.ap-terminal .bg-200 { - background-color: #ff00d7; -} -.ap-terminal .fg-201 { - color: #ff00ff; -} -.ap-terminal .bg-201 { - background-color: #ff00ff; -} -.ap-terminal .fg-202 { - color: #ff5f00; -} -.ap-terminal .bg-202 { - background-color: #ff5f00; -} -.ap-terminal .fg-203 { - color: #ff5f5f; -} -.ap-terminal .bg-203 { - background-color: #ff5f5f; -} -.ap-terminal .fg-204 { - color: #ff5f87; -} -.ap-terminal .bg-204 { - background-color: #ff5f87; -} -.ap-terminal .fg-205 { - color: #ff5faf; -} -.ap-terminal .bg-205 { - background-color: #ff5faf; -} -.ap-terminal .fg-206 { - color: #ff5fd7; -} -.ap-terminal .bg-206 { - background-color: #ff5fd7; -} -.ap-terminal .fg-207 { - color: #ff5fff; -} -.ap-terminal .bg-207 { - background-color: #ff5fff; -} -.ap-terminal .fg-208 { - color: #ff8700; -} -.ap-terminal .bg-208 { - background-color: #ff8700; -} -.ap-terminal .fg-209 { - color: #ff875f; -} -.ap-terminal .bg-209 { - background-color: #ff875f; -} -.ap-terminal .fg-210 { - color: #ff8787; -} -.ap-terminal .bg-210 { - background-color: #ff8787; -} -.ap-terminal .fg-211 { - color: #ff87af; -} -.ap-terminal .bg-211 { - background-color: #ff87af; -} -.ap-terminal .fg-212 { - color: #ff87d7; -} -.ap-terminal .bg-212 { - background-color: #ff87d7; -} -.ap-terminal .fg-213 { - color: #ff87ff; -} -.ap-terminal .bg-213 { - background-color: #ff87ff; -} -.ap-terminal .fg-214 { - color: #ffaf00; -} -.ap-terminal .bg-214 { - background-color: #ffaf00; -} -.ap-terminal .fg-215 { - color: #ffaf5f; -} -.ap-terminal .bg-215 { - background-color: #ffaf5f; -} -.ap-terminal .fg-216 { - color: #ffaf87; -} -.ap-terminal .bg-216 { - background-color: #ffaf87; -} -.ap-terminal .fg-217 { - color: #ffafaf; -} -.ap-terminal .bg-217 { - background-color: #ffafaf; -} -.ap-terminal .fg-218 { - color: #ffafd7; -} -.ap-terminal .bg-218 { - background-color: #ffafd7; -} -.ap-terminal .fg-219 { - color: #ffafff; -} -.ap-terminal .bg-219 { - background-color: #ffafff; -} -.ap-terminal .fg-220 { - color: #ffd700; -} -.ap-terminal .bg-220 { - background-color: #ffd700; -} -.ap-terminal .fg-221 { - color: #ffd75f; -} -.ap-terminal .bg-221 { - background-color: #ffd75f; -} -.ap-terminal .fg-222 { - color: #ffd787; -} -.ap-terminal .bg-222 { - background-color: #ffd787; -} -.ap-terminal .fg-223 { - color: #ffd7af; -} -.ap-terminal .bg-223 { - background-color: #ffd7af; -} -.ap-terminal .fg-224 { - color: #ffd7d7; -} -.ap-terminal .bg-224 { - background-color: #ffd7d7; -} -.ap-terminal .fg-225 { - color: #ffd7ff; -} -.ap-terminal .bg-225 { - background-color: #ffd7ff; -} -.ap-terminal .fg-226 { - color: #ffff00; -} -.ap-terminal .bg-226 { - background-color: #ffff00; -} -.ap-terminal .fg-227 { - color: #ffff5f; -} -.ap-terminal .bg-227 { - background-color: #ffff5f; -} -.ap-terminal .fg-228 { - color: #ffff87; -} -.ap-terminal .bg-228 { - background-color: #ffff87; -} -.ap-terminal .fg-229 { - color: #ffffaf; -} -.ap-terminal .bg-229 { - background-color: #ffffaf; -} -.ap-terminal .fg-230 { - color: #ffffd7; -} -.ap-terminal .bg-230 { - background-color: #ffffd7; -} -.ap-terminal .fg-231 { - color: #ffffff; -} -.ap-terminal .bg-231 { - background-color: #ffffff; -} -.ap-terminal .fg-232 { - color: #080808; -} -.ap-terminal .bg-232 { - background-color: #080808; -} -.ap-terminal .fg-233 { - color: #121212; -} -.ap-terminal .bg-233 { - background-color: #121212; -} -.ap-terminal .fg-234 { - color: #1c1c1c; -} -.ap-terminal .bg-234 { - background-color: #1c1c1c; -} -.ap-terminal .fg-235 { - color: #262626; -} -.ap-terminal .bg-235 { - background-color: #262626; -} -.ap-terminal .fg-236 { - color: #303030; -} -.ap-terminal .bg-236 { - background-color: #303030; -} -.ap-terminal .fg-237 { - color: #3a3a3a; -} -.ap-terminal .bg-237 { - background-color: #3a3a3a; -} -.ap-terminal .fg-238 { - color: #444444; -} -.ap-terminal .bg-238 { - background-color: #444444; -} -.ap-terminal .fg-239 { - color: #4e4e4e; -} -.ap-terminal .bg-239 { - background-color: #4e4e4e; -} -.ap-terminal .fg-240 { - color: #585858; -} -.ap-terminal .bg-240 { - background-color: #585858; -} -.ap-terminal .fg-241 { - color: #626262; -} -.ap-terminal .bg-241 { - background-color: #626262; -} -.ap-terminal .fg-242 { - color: #6c6c6c; -} -.ap-terminal .bg-242 { - background-color: #6c6c6c; -} -.ap-terminal .fg-243 { - color: #767676; -} -.ap-terminal .bg-243 { - background-color: #767676; -} -.ap-terminal .fg-244 { - color: #808080; -} -.ap-terminal .bg-244 { - background-color: #808080; -} -.ap-terminal .fg-245 { - color: #8a8a8a; -} -.ap-terminal .bg-245 { - background-color: #8a8a8a; -} -.ap-terminal .fg-246 { - color: #949494; -} -.ap-terminal .bg-246 { - background-color: #949494; -} -.ap-terminal .fg-247 { - color: #9e9e9e; -} -.ap-terminal .bg-247 { - background-color: #9e9e9e; -} -.ap-terminal .fg-248 { - color: #a8a8a8; -} -.ap-terminal .bg-248 { - background-color: #a8a8a8; -} -.ap-terminal .fg-249 { - color: #b2b2b2; -} -.ap-terminal .bg-249 { - background-color: #b2b2b2; -} -.ap-terminal .fg-250 { - color: #bcbcbc; -} -.ap-terminal .bg-250 { - background-color: #bcbcbc; -} -.ap-terminal .fg-251 { - color: #c6c6c6; -} -.ap-terminal .bg-251 { - background-color: #c6c6c6; -} -.ap-terminal .fg-252 { - color: #d0d0d0; -} -.ap-terminal .bg-252 { - background-color: #d0d0d0; -} -.ap-terminal .fg-253 { - color: #dadada; -} -.ap-terminal .bg-253 { - background-color: #dadada; -} -.ap-terminal .fg-254 { - color: #e4e4e4; -} -.ap-terminal .bg-254 { - background-color: #e4e4e4; -} -.ap-terminal .fg-255 { - color: #eeeeee; -} -.ap-terminal .bg-255 { - background-color: #eeeeee; -} -.asciinema-theme-asciinema { - background-color: #121314; -} -.asciinema-theme-asciinema pre.ap-terminal { - color: #CCCCCC; - background-color: #121314; - border-color: #121314; -} -.asciinema-theme-asciinema .fg-default { - color: #CCCCCC; -} -.asciinema-theme-asciinema .fg-bg { - color: #121314; -} -.asciinema-theme-asciinema .bg-default { - background-color: #121314; -} -.asciinema-theme-asciinema .bg-fg { - background-color: #CCCCCC; -} -.asciinema-theme-asciinema .fg-0 { - color: hsl(0, 0%, 0%); -} -.asciinema-theme-asciinema .bg-0 { - background-color: hsl(0, 0%, 0%); -} -.asciinema-theme-asciinema .fg-1 { - color: hsl(343, 70%, 55%); -} -.asciinema-theme-asciinema .bg-1 { - background-color: hsl(343, 70%, 55%); -} -.asciinema-theme-asciinema .fg-2 { - color: hsl(103, 70%, 44%); -} -.asciinema-theme-asciinema .bg-2 { - background-color: hsl(103, 70%, 44%); -} -.asciinema-theme-asciinema .fg-3 { - color: hsl(43, 70%, 55%); -} -.asciinema-theme-asciinema .bg-3 { - background-color: hsl(43, 70%, 55%); -} -.asciinema-theme-asciinema .fg-4 { - color: hsl(193, 70%, 49.5%); -} -.asciinema-theme-asciinema .bg-4 { - background-color: hsl(193, 70%, 49.5%); -} -.asciinema-theme-asciinema .fg-5 { - color: hsl(283, 70%, 60.5%); -} -.asciinema-theme-asciinema .bg-5 { - background-color: hsl(283, 70%, 60.5%); -} -.asciinema-theme-asciinema .fg-6 { - color: hsl(163, 70%, 60.5%); -} -.asciinema-theme-asciinema .bg-6 { - background-color: hsl(163, 70%, 60.5%); -} -.asciinema-theme-asciinema .fg-7 { - color: hsl(0, 0%, 85%); -} -.asciinema-theme-asciinema .bg-7 { - background-color: hsl(0, 0%, 85%); -} -.asciinema-theme-asciinema .fg-8 { - color: hsl(0, 0%, 30%); -} -.asciinema-theme-asciinema .bg-8 { - background-color: hsl(0, 0%, 30%); -} -.asciinema-theme-asciinema .fg-9 { - color: hsl(343, 70%, 55%); -} -.asciinema-theme-asciinema .bg-9 { - background-color: hsl(343, 70%, 55%); -} -.asciinema-theme-asciinema .fg-10 { - color: hsl(103, 70%, 44%); -} -.asciinema-theme-asciinema .bg-10 { - background-color: hsl(103, 70%, 44%); -} -.asciinema-theme-asciinema .fg-11 { - color: hsl(43, 70%, 55%); -} -.asciinema-theme-asciinema .bg-11 { - background-color: hsl(43, 70%, 55%); -} -.asciinema-theme-asciinema .fg-12 { - color: hsl(193, 70%, 49.5%); -} -.asciinema-theme-asciinema .bg-12 { - background-color: hsl(193, 70%, 49.5%); -} -.asciinema-theme-asciinema .fg-13 { - color: hsl(283, 70%, 60.5%); -} -.asciinema-theme-asciinema .bg-13 { - background-color: hsl(283, 70%, 60.5%); -} -.asciinema-theme-asciinema .fg-14 { - color: hsl(163, 70%, 60.5%); -} -.asciinema-theme-asciinema .bg-14 { - background-color: hsl(163, 70%, 60.5%); -} -.asciinema-theme-asciinema .fg-15 { - color: hsl(0, 0%, 100%); -} -.asciinema-theme-asciinema .bg-15 { - background-color: hsl(0, 0%, 100%); -} -.asciinema-theme-asciinema .ap-overlay-loading .ap-loader { - border-color: rgba(204, 204, 204, 0.3) rgba(204, 204, 204, 0.5) rgba(204, 204, 204, 0.7) #cccccc; -} -.asciinema-theme-asciinema .fg-8, -.asciinema-theme-asciinema .fg-9, -.asciinema-theme-asciinema .fg-10, -.asciinema-theme-asciinema .fg-11, -.asciinema-theme-asciinema .fg-12, -.asciinema-theme-asciinema .fg-13, -.asciinema-theme-asciinema .fg-14, -.asciinema-theme-asciinema .fg-15 { - font-weight: bold; -} -/* - Based on Dracula: https://draculatheme.com - */ -.asciinema-theme-dracula { - background-color: #282a36; -} -.asciinema-theme-dracula pre.ap-terminal { - color: #f8f8f2; - background-color: #282a36; - border-color: #282a36; -} -.asciinema-theme-dracula .fg-default { - color: #f8f8f2; -} -.asciinema-theme-dracula .fg-bg { - color: #282a36; -} -.asciinema-theme-dracula .bg-default { - background-color: #282a36; -} -.asciinema-theme-dracula .bg-fg { - background-color: #f8f8f2; -} -.asciinema-theme-dracula .fg-0 { - color: #21222c; -} -.asciinema-theme-dracula .bg-0 { - background-color: #21222c; -} -.asciinema-theme-dracula .fg-1 { - color: #ff5555; -} -.asciinema-theme-dracula .bg-1 { - background-color: #ff5555; -} -.asciinema-theme-dracula .fg-2 { - color: #50fa7b; -} -.asciinema-theme-dracula .bg-2 { - background-color: #50fa7b; -} -.asciinema-theme-dracula .fg-3 { - color: #f1fa8c; -} -.asciinema-theme-dracula .bg-3 { - background-color: #f1fa8c; -} -.asciinema-theme-dracula .fg-4 { - color: #bd93f9; -} -.asciinema-theme-dracula .bg-4 { - background-color: #bd93f9; -} -.asciinema-theme-dracula .fg-5 { - color: #ff79c6; -} -.asciinema-theme-dracula .bg-5 { - background-color: #ff79c6; -} -.asciinema-theme-dracula .fg-6 { - color: #8be9fd; -} -.asciinema-theme-dracula .bg-6 { - background-color: #8be9fd; -} -.asciinema-theme-dracula .fg-7 { - color: #f8f8f2; -} -.asciinema-theme-dracula .bg-7 { - background-color: #f8f8f2; -} -.asciinema-theme-dracula .fg-8 { - color: #6272a4; -} -.asciinema-theme-dracula .bg-8 { - background-color: #6272a4; -} -.asciinema-theme-dracula .fg-9 { - color: #ff6e6e; -} -.asciinema-theme-dracula .bg-9 { - background-color: #ff6e6e; -} -.asciinema-theme-dracula .fg-10 { - color: #69ff94; -} -.asciinema-theme-dracula .bg-10 { - background-color: #69ff94; -} -.asciinema-theme-dracula .fg-11 { - color: #ffffa5; -} -.asciinema-theme-dracula .bg-11 { - background-color: #ffffa5; -} -.asciinema-theme-dracula .fg-12 { - color: #d6acff; -} -.asciinema-theme-dracula .bg-12 { - background-color: #d6acff; -} -.asciinema-theme-dracula .fg-13 { - color: #ff92df; -} -.asciinema-theme-dracula .bg-13 { - background-color: #ff92df; -} -.asciinema-theme-dracula .fg-14 { - color: #a4ffff; -} -.asciinema-theme-dracula .bg-14 { - background-color: #a4ffff; -} -.asciinema-theme-dracula .fg-15 { - color: #ffffff; -} -.asciinema-theme-dracula .bg-15 { - background-color: #ffffff; -} -.asciinema-theme-dracula .ap-overlay-loading .ap-loader { - border-color: rgba(248, 248, 242, 0.3) rgba(248, 248, 242, 0.5) rgba(248, 248, 242, 0.7) #f8f8f2; -} -.asciinema-theme-dracula .fg-8, -.asciinema-theme-dracula .fg-9, -.asciinema-theme-dracula .fg-10, -.asciinema-theme-dracula .fg-11, -.asciinema-theme-dracula .fg-12, -.asciinema-theme-dracula .fg-13, -.asciinema-theme-dracula .fg-14, -.asciinema-theme-dracula .fg-15 { - font-weight: bold; -} -/* Based on Monokai from base16 collection - https://github.com/chriskempson/base16 */ -.asciinema-theme-monokai { - background-color: #272822; -} -.asciinema-theme-monokai pre.ap-terminal { - color: #f8f8f2; - background-color: #272822; - border-color: #272822; -} -.asciinema-theme-monokai .fg-default { - color: #f8f8f2; -} -.asciinema-theme-monokai .fg-bg { - color: #272822; -} -.asciinema-theme-monokai .bg-default { - background-color: #272822; -} -.asciinema-theme-monokai .bg-fg { - background-color: #f8f8f2; -} -.asciinema-theme-monokai .fg-0 { - color: #272822; -} -.asciinema-theme-monokai .bg-0 { - background-color: #272822; -} -.asciinema-theme-monokai .fg-1 { - color: #f92672; -} -.asciinema-theme-monokai .bg-1 { - background-color: #f92672; -} -.asciinema-theme-monokai .fg-2 { - color: #a6e22e; -} -.asciinema-theme-monokai .bg-2 { - background-color: #a6e22e; -} -.asciinema-theme-monokai .fg-3 { - color: #f4bf75; -} -.asciinema-theme-monokai .bg-3 { - background-color: #f4bf75; -} -.asciinema-theme-monokai .fg-4 { - color: #66d9ef; -} -.asciinema-theme-monokai .bg-4 { - background-color: #66d9ef; -} -.asciinema-theme-monokai .fg-5 { - color: #ae81ff; -} -.asciinema-theme-monokai .bg-5 { - background-color: #ae81ff; -} -.asciinema-theme-monokai .fg-6 { - color: #a1efe4; -} -.asciinema-theme-monokai .bg-6 { - background-color: #a1efe4; -} -.asciinema-theme-monokai .fg-7 { - color: #f8f8f2; -} -.asciinema-theme-monokai .bg-7 { - background-color: #f8f8f2; -} -.asciinema-theme-monokai .fg-8 { - color: #75715e; -} -.asciinema-theme-monokai .bg-8 { - background-color: #75715e; -} -.asciinema-theme-monokai .fg-9 { - color: #f92672; -} -.asciinema-theme-monokai .bg-9 { - background-color: #f92672; -} -.asciinema-theme-monokai .fg-10 { - color: #a6e22e; -} -.asciinema-theme-monokai .bg-10 { - background-color: #a6e22e; -} -.asciinema-theme-monokai .fg-11 { - color: #f4bf75; -} -.asciinema-theme-monokai .bg-11 { - background-color: #f4bf75; -} -.asciinema-theme-monokai .fg-12 { - color: #66d9ef; -} -.asciinema-theme-monokai .bg-12 { - background-color: #66d9ef; -} -.asciinema-theme-monokai .fg-13 { - color: #ae81ff; -} -.asciinema-theme-monokai .bg-13 { - background-color: #ae81ff; -} -.asciinema-theme-monokai .fg-14 { - color: #a1efe4; -} -.asciinema-theme-monokai .bg-14 { - background-color: #a1efe4; -} -.asciinema-theme-monokai .fg-15 { - color: #f9f8f5; -} -.asciinema-theme-monokai .bg-15 { - background-color: #f9f8f5; -} -.asciinema-theme-monokai .ap-overlay-loading .ap-loader { - border-color: rgba(248, 248, 242, 0.3) rgba(248, 248, 242, 0.5) rgba(248, 248, 242, 0.7) #f8f8f2; -} -.asciinema-theme-monokai .fg-8, -.asciinema-theme-monokai .fg-9, -.asciinema-theme-monokai .fg-10, -.asciinema-theme-monokai .fg-11, -.asciinema-theme-monokai .fg-12, -.asciinema-theme-monokai .fg-13, -.asciinema-theme-monokai .fg-14, -.asciinema-theme-monokai .fg-15 { - font-weight: bold; -} -/* - Based on Nord: https://github.com/arcticicestudio/nord - Via: https://github.com/neilotoole/asciinema-theme-nord - */ -.asciinema-theme-nord { - background-color: #2E3440; -} -.asciinema-theme-nord pre.ap-terminal { - color: #ECEFF4; - background-color: #2E3440; - border-color: #2E3440; -} -.asciinema-theme-nord .fg-default { - color: #ECEFF4; -} -.asciinema-theme-nord .fg-bg { - color: #2E3440; -} -.asciinema-theme-nord .bg-default { - background-color: #2E3440; -} -.asciinema-theme-nord .bg-fg { - background-color: #ECEFF4; -} -.asciinema-theme-nord .fg-0 { - color: #3B4252; -} -.asciinema-theme-nord .bg-0 { - background-color: #3B4252; -} -.asciinema-theme-nord .fg-1 { - color: #BF616A; -} -.asciinema-theme-nord .bg-1 { - background-color: #BF616A; -} -.asciinema-theme-nord .fg-2 { - color: #A3BE8C; -} -.asciinema-theme-nord .bg-2 { - background-color: #A3BE8C; -} -.asciinema-theme-nord .fg-3 { - color: #EBCB8B; -} -.asciinema-theme-nord .bg-3 { - background-color: #EBCB8B; -} -.asciinema-theme-nord .fg-4 { - color: #81A1C1; -} -.asciinema-theme-nord .bg-4 { - background-color: #81A1C1; -} -.asciinema-theme-nord .fg-5 { - color: #B48EAD; -} -.asciinema-theme-nord .bg-5 { - background-color: #B48EAD; -} -.asciinema-theme-nord .fg-6 { - color: #88C0D0; -} -.asciinema-theme-nord .bg-6 { - background-color: #88C0D0; -} -.asciinema-theme-nord .fg-7 { - color: #ECEFF4; -} -.asciinema-theme-nord .bg-7 { - background-color: #ECEFF4; -} -.asciinema-theme-nord .fg-8 { - color: #3B4252; -} -.asciinema-theme-nord .bg-8 { - background-color: #3B4252; -} -.asciinema-theme-nord .fg-9 { - color: #BF616A; -} -.asciinema-theme-nord .bg-9 { - background-color: #BF616A; -} -.asciinema-theme-nord .fg-10 { - color: #A3BE8C; -} -.asciinema-theme-nord .bg-10 { - background-color: #A3BE8C; -} -.asciinema-theme-nord .fg-11 { - color: #EBCB8B; -} -.asciinema-theme-nord .bg-11 { - background-color: #EBCB8B; -} -.asciinema-theme-nord .fg-12 { - color: #81A1C1; -} -.asciinema-theme-nord .bg-12 { - background-color: #81A1C1; -} -.asciinema-theme-nord .fg-13 { - color: #B48EAD; -} -.asciinema-theme-nord .bg-13 { - background-color: #B48EAD; -} -.asciinema-theme-nord .fg-14 { - color: #88C0D0; -} -.asciinema-theme-nord .bg-14 { - background-color: #88C0D0; -} -.asciinema-theme-nord .fg-15 { - color: #ECEFF4; -} -.asciinema-theme-nord .bg-15 { - background-color: #ECEFF4; -} -.asciinema-theme-nord .ap-overlay-loading .ap-loader { - border-color: rgba(236, 239, 244, 0.3) rgba(236, 239, 244, 0.5) rgba(236, 239, 244, 0.7) #eceff4; -} -.asciinema-theme-nord .fg-8, -.asciinema-theme-nord .fg-9, -.asciinema-theme-nord .fg-10, -.asciinema-theme-nord .fg-11, -.asciinema-theme-nord .fg-12, -.asciinema-theme-nord .fg-13, -.asciinema-theme-nord .fg-14, -.asciinema-theme-nord .fg-15 { - font-weight: bold; -} -.asciinema-theme-seti { - background-color: #111213; -} -.asciinema-theme-seti pre.ap-terminal { - color: #cacecd; - background-color: #111213; - border-color: #111213; -} -.asciinema-theme-seti .fg-default { - color: #cacecd; -} -.asciinema-theme-seti .fg-bg { - color: #111213; -} -.asciinema-theme-seti .bg-default { - background-color: #111213; -} -.asciinema-theme-seti .bg-fg { - background-color: #cacecd; -} -.asciinema-theme-seti .fg-0 { - color: #323232; -} -.asciinema-theme-seti .bg-0 { - background-color: #323232; -} -.asciinema-theme-seti .fg-1 { - color: #c22832; -} -.asciinema-theme-seti .bg-1 { - background-color: #c22832; -} -.asciinema-theme-seti .fg-2 { - color: #8ec43d; -} -.asciinema-theme-seti .bg-2 { - background-color: #8ec43d; -} -.asciinema-theme-seti .fg-3 { - color: #e0c64f; -} -.asciinema-theme-seti .bg-3 { - background-color: #e0c64f; -} -.asciinema-theme-seti .fg-4 { - color: #43a5d5; -} -.asciinema-theme-seti .bg-4 { - background-color: #43a5d5; -} -.asciinema-theme-seti .fg-5 { - color: #8b57b5; -} -.asciinema-theme-seti .bg-5 { - background-color: #8b57b5; -} -.asciinema-theme-seti .fg-6 { - color: #8ec43d; -} -.asciinema-theme-seti .bg-6 { - background-color: #8ec43d; -} -.asciinema-theme-seti .fg-7 { - color: #eeeeee; -} -.asciinema-theme-seti .bg-7 { - background-color: #eeeeee; -} -.asciinema-theme-seti .fg-8 { - color: #323232; -} -.asciinema-theme-seti .bg-8 { - background-color: #323232; -} -.asciinema-theme-seti .fg-9 { - color: #c22832; -} -.asciinema-theme-seti .bg-9 { - background-color: #c22832; -} -.asciinema-theme-seti .fg-10 { - color: #8ec43d; -} -.asciinema-theme-seti .bg-10 { - background-color: #8ec43d; -} -.asciinema-theme-seti .fg-11 { - color: #e0c64f; -} -.asciinema-theme-seti .bg-11 { - background-color: #e0c64f; -} -.asciinema-theme-seti .fg-12 { - color: #43a5d5; -} -.asciinema-theme-seti .bg-12 { - background-color: #43a5d5; -} -.asciinema-theme-seti .fg-13 { - color: #8b57b5; -} -.asciinema-theme-seti .bg-13 { - background-color: #8b57b5; -} -.asciinema-theme-seti .fg-14 { - color: #8ec43d; -} -.asciinema-theme-seti .bg-14 { - background-color: #8ec43d; -} -.asciinema-theme-seti .fg-15 { - color: #ffffff; -} -.asciinema-theme-seti .bg-15 { - background-color: #ffffff; -} -.asciinema-theme-seti .ap-overlay-loading .ap-loader { - border-color: rgba(202, 206, 205, 0.3) rgba(202, 206, 205, 0.5) rgba(202, 206, 205, 0.7) #cacecd; -} -.asciinema-theme-seti .fg-8, -.asciinema-theme-seti .fg-9, -.asciinema-theme-seti .fg-10, -.asciinema-theme-seti .fg-11, -.asciinema-theme-seti .fg-12, -.asciinema-theme-seti .fg-13, -.asciinema-theme-seti .fg-14, -.asciinema-theme-seti .fg-15 { - font-weight: bold; -} -.asciinema-theme-solarized-dark { - background-color: #002b36; -} -.asciinema-theme-solarized-dark pre.ap-terminal { - color: #839496; - background-color: #002b36; - border-color: #002b36; -} -.asciinema-theme-solarized-dark .fg-default { - color: #839496; -} -.asciinema-theme-solarized-dark .fg-bg { - color: #002b36; -} -.asciinema-theme-solarized-dark .bg-default { - background-color: #002b36; -} -.asciinema-theme-solarized-dark .bg-fg { - background-color: #839496; -} -.asciinema-theme-solarized-dark .fg-0 { - color: #073642; -} -.asciinema-theme-solarized-dark .bg-0 { - background-color: #073642; -} -.asciinema-theme-solarized-dark .fg-1 { - color: #dc322f; -} -.asciinema-theme-solarized-dark .bg-1 { - background-color: #dc322f; -} -.asciinema-theme-solarized-dark .fg-2 { - color: #859900; -} -.asciinema-theme-solarized-dark .bg-2 { - background-color: #859900; -} -.asciinema-theme-solarized-dark .fg-3 { - color: #b58900; -} -.asciinema-theme-solarized-dark .bg-3 { - background-color: #b58900; -} -.asciinema-theme-solarized-dark .fg-4 { - color: #268bd2; -} -.asciinema-theme-solarized-dark .bg-4 { - background-color: #268bd2; -} -.asciinema-theme-solarized-dark .fg-5 { - color: #d33682; -} -.asciinema-theme-solarized-dark .bg-5 { - background-color: #d33682; -} -.asciinema-theme-solarized-dark .fg-6 { - color: #2aa198; -} -.asciinema-theme-solarized-dark .bg-6 { - background-color: #2aa198; -} -.asciinema-theme-solarized-dark .fg-7 { - color: #eee8d5; -} -.asciinema-theme-solarized-dark .bg-7 { - background-color: #eee8d5; -} -.asciinema-theme-solarized-dark .fg-8 { - color: #002b36; -} -.asciinema-theme-solarized-dark .bg-8 { - background-color: #002b36; -} -.asciinema-theme-solarized-dark .fg-9 { - color: #cb4b16; -} -.asciinema-theme-solarized-dark .bg-9 { - background-color: #cb4b16; -} -.asciinema-theme-solarized-dark .fg-10 { - color: #586e75; -} -.asciinema-theme-solarized-dark .bg-10 { - background-color: #586e75; -} -.asciinema-theme-solarized-dark .fg-11 { - color: #657b83; -} -.asciinema-theme-solarized-dark .bg-11 { - background-color: #657b83; -} -.asciinema-theme-solarized-dark .fg-12 { - color: #839496; -} -.asciinema-theme-solarized-dark .bg-12 { - background-color: #839496; -} -.asciinema-theme-solarized-dark .fg-13 { - color: #6c71c4; -} -.asciinema-theme-solarized-dark .bg-13 { - background-color: #6c71c4; -} -.asciinema-theme-solarized-dark .fg-14 { - color: #93a1a1; -} -.asciinema-theme-solarized-dark .bg-14 { - background-color: #93a1a1; -} -.asciinema-theme-solarized-dark .fg-15 { - color: #fdf6e3; -} -.asciinema-theme-solarized-dark .bg-15 { - background-color: #fdf6e3; -} -.asciinema-theme-solarized-dark .ap-overlay-loading .ap-loader { - border-color: rgba(131, 148, 150, 0.3) rgba(131, 148, 150, 0.5) rgba(131, 148, 150, 0.7) #839496; -} -.asciinema-theme-solarized-light { - background-color: #fdf6e3; -} -.asciinema-theme-solarized-light pre.ap-terminal { - color: #657b83; - background-color: #fdf6e3; - border-color: #fdf6e3; -} -.asciinema-theme-solarized-light .fg-default { - color: #657b83; -} -.asciinema-theme-solarized-light .fg-bg { - color: #fdf6e3; -} -.asciinema-theme-solarized-light .bg-default { - background-color: #fdf6e3; -} -.asciinema-theme-solarized-light .bg-fg { - background-color: #657b83; -} -.asciinema-theme-solarized-light .fg-0 { - color: #073642; -} -.asciinema-theme-solarized-light .bg-0 { - background-color: #073642; -} -.asciinema-theme-solarized-light .fg-1 { - color: #dc322f; -} -.asciinema-theme-solarized-light .bg-1 { - background-color: #dc322f; -} -.asciinema-theme-solarized-light .fg-2 { - color: #859900; -} -.asciinema-theme-solarized-light .bg-2 { - background-color: #859900; -} -.asciinema-theme-solarized-light .fg-3 { - color: #b58900; -} -.asciinema-theme-solarized-light .bg-3 { - background-color: #b58900; -} -.asciinema-theme-solarized-light .fg-4 { - color: #268bd2; -} -.asciinema-theme-solarized-light .bg-4 { - background-color: #268bd2; -} -.asciinema-theme-solarized-light .fg-5 { - color: #d33682; -} -.asciinema-theme-solarized-light .bg-5 { - background-color: #d33682; -} -.asciinema-theme-solarized-light .fg-6 { - color: #2aa198; -} -.asciinema-theme-solarized-light .bg-6 { - background-color: #2aa198; -} -.asciinema-theme-solarized-light .fg-7 { - color: #eee8d5; -} -.asciinema-theme-solarized-light .bg-7 { - background-color: #eee8d5; -} -.asciinema-theme-solarized-light .fg-8 { - color: #002b36; -} -.asciinema-theme-solarized-light .bg-8 { - background-color: #002b36; -} -.asciinema-theme-solarized-light .fg-9 { - color: #cb4b16; -} -.asciinema-theme-solarized-light .bg-9 { - background-color: #cb4b16; -} -.asciinema-theme-solarized-light .fg-10 { - color: #586e75; -} -.asciinema-theme-solarized-light .bg-10 { - background-color: #586e75; -} -.asciinema-theme-solarized-light .fg-11 { - color: #657c83; -} -.asciinema-theme-solarized-light .bg-11 { - background-color: #657c83; -} -.asciinema-theme-solarized-light .fg-12 { - color: #839496; -} -.asciinema-theme-solarized-light .bg-12 { - background-color: #839496; -} -.asciinema-theme-solarized-light .fg-13 { - color: #6c71c4; -} -.asciinema-theme-solarized-light .bg-13 { - background-color: #6c71c4; -} -.asciinema-theme-solarized-light .fg-14 { - color: #93a1a1; -} -.asciinema-theme-solarized-light .bg-14 { - background-color: #93a1a1; -} -.asciinema-theme-solarized-light .fg-15 { - color: #fdf6e3; -} -.asciinema-theme-solarized-light .bg-15 { - background-color: #fdf6e3; -} -.asciinema-theme-solarized-light .ap-overlay-loading .ap-loader { - border-color: rgba(101, 123, 131, 0.3) rgba(101, 123, 131, 0.5) rgba(101, 123, 131, 0.7) #657b83; -} -.asciinema-theme-solarized-light .ap-overlay-start .ap-play-button svg .ap-play-btn-fill { - fill: #dc322f; -} -.asciinema-theme-solarized-light .ap-overlay-start .ap-play-button svg .ap-play-btn-stroke { - stroke: #dc322f; -} -.asciinema-theme-tango { - background-color: #121314; -} -.asciinema-theme-tango pre.ap-terminal { - color: #CCCCCC; - background-color: #121314; - border-color: #121314; -} -.asciinema-theme-tango .fg-default { - color: #CCCCCC; -} -.asciinema-theme-tango .fg-bg { - color: #121314; -} -.asciinema-theme-tango .bg-default { - background-color: #121314; -} -.asciinema-theme-tango .bg-fg { - background-color: #CCCCCC; -} -.asciinema-theme-tango .fg-0 { - color: #000000; -} -.asciinema-theme-tango .bg-0 { - background-color: #000000; -} -.asciinema-theme-tango .fg-1 { - color: #CC0000; -} -.asciinema-theme-tango .bg-1 { - background-color: #CC0000; -} -.asciinema-theme-tango .fg-2 { - color: #4E9A06; -} -.asciinema-theme-tango .bg-2 { - background-color: #4E9A06; -} -.asciinema-theme-tango .fg-3 { - color: #C4A000; -} -.asciinema-theme-tango .bg-3 { - background-color: #C4A000; -} -.asciinema-theme-tango .fg-4 { - color: #3465A4; -} -.asciinema-theme-tango .bg-4 { - background-color: #3465A4; -} -.asciinema-theme-tango .fg-5 { - color: #75507B; -} -.asciinema-theme-tango .bg-5 { - background-color: #75507B; -} -.asciinema-theme-tango .fg-6 { - color: #06989A; -} -.asciinema-theme-tango .bg-6 { - background-color: #06989A; -} -.asciinema-theme-tango .fg-7 { - color: #D3D7CF; -} -.asciinema-theme-tango .bg-7 { - background-color: #D3D7CF; -} -.asciinema-theme-tango .fg-8 { - color: #555753; -} -.asciinema-theme-tango .bg-8 { - background-color: #555753; -} -.asciinema-theme-tango .fg-9 { - color: #EF2929; -} -.asciinema-theme-tango .bg-9 { - background-color: #EF2929; -} -.asciinema-theme-tango .fg-10 { - color: #8AE234; -} -.asciinema-theme-tango .bg-10 { - background-color: #8AE234; -} -.asciinema-theme-tango .fg-11 { - color: #FCE94F; -} -.asciinema-theme-tango .bg-11 { - background-color: #FCE94F; -} -.asciinema-theme-tango .fg-12 { - color: #729FCF; -} -.asciinema-theme-tango .bg-12 { - background-color: #729FCF; -} -.asciinema-theme-tango .fg-13 { - color: #AD7FA8; -} -.asciinema-theme-tango .bg-13 { - background-color: #AD7FA8; -} -.asciinema-theme-tango .fg-14 { - color: #34E2E2; -} -.asciinema-theme-tango .bg-14 { - background-color: #34E2E2; -} -.asciinema-theme-tango .fg-15 { - color: #EEEEEC; -} -.asciinema-theme-tango .bg-15 { - background-color: #EEEEEC; -} -.asciinema-theme-tango .ap-overlay-loading .ap-loader { - border-color: rgba(204, 204, 204, 0.3) rgba(204, 204, 204, 0.5) rgba(204, 204, 204, 0.7) #cccccc; -} -.asciinema-theme-tango .fg-8, -.asciinema-theme-tango .fg-9, -.asciinema-theme-tango .fg-10, -.asciinema-theme-tango .fg-11, -.asciinema-theme-tango .fg-12, -.asciinema-theme-tango .fg-13, -.asciinema-theme-tango .fg-14, -.asciinema-theme-tango .fg-15 { - font-weight: bold; -} diff --git a/homepage/home_static/asciinema-player.min.js b/homepage/home_static/asciinema-player.min.js deleted file mode 100644 index 6ab76742c..000000000 --- a/homepage/home_static/asciinema-player.min.js +++ /dev/null @@ -1 +0,0 @@ -var AsciinemaPlayer=function(A){"use strict";const g={};const I=Symbol("solid-proxy"),B=Symbol("solid-track"),Q={equals:(A,g)=>A===g};let C=J;const E=1,e=2,i={owned:null,cleanups:null,context:null,owner:null};var t=null;let o=null,s=null,n=null,r=null,a=0;function c(A,g){const I=s,B=t,Q=0===A.length,C=Q?i:{owned:null,cleanups:null,context:null,owner:void 0===g?B:g},E=Q?A:()=>A((()=>y((()=>U(C)))));t=C,s=null;try{return R(E,!0)}finally{s=I,t=B}}function D(A,g){const I={value:A,observers:null,observerSlots:null,comparator:(g=g?Object.assign({},Q,g):Q).equals||void 0};return[u.bind(I),A=>("function"==typeof A&&(A=A(I.value)),F(I,A))]}function w(A,g,I){d(f(A,g,!1,E))}function h(A,g,I){I=I?Object.assign({},Q,I):Q;const B=f(A,g,!0,0);return B.observers=null,B.observerSlots=null,B.comparator=I.equals||void 0,d(B),u.bind(B)}function l(A){return R(A,!1)}function y(A){if(null===s)return A();const g=s;s=null;try{return A()}finally{s=g}}function G(A){!function(A,g,I){C=p;const B=f(A,g,!1,E);B.user=!0,r?r.push(B):d(B)}((()=>y(A)))}function M(A){return null===t||(null===t.cleanups?t.cleanups=[A]:t.cleanups.push(A)),A}function k(){return s}function N(A){const g=h(A),I=h((()=>K(g())));return I.toArray=()=>{const A=I();return Array.isArray(A)?A:null!=A?[A]:[]},I}function u(){const A=o;if(this.sources&&(this.state||A))if(this.state===E||A)d(this);else{const A=n;n=null,R((()=>S(this)),!1),n=A}if(s){const A=this.observers?this.observers.length:0;s.sources?(s.sources.push(this),s.sourceSlots.push(A)):(s.sources=[this],s.sourceSlots=[A]),this.observers?(this.observers.push(s),this.observerSlots.push(s.sources.length-1)):(this.observers=[s],this.observerSlots=[s.sources.length-1])}return this.value}function F(A,g,I){let B=A.value;return A.comparator&&A.comparator(B,g)||(A.value=g,A.observers&&A.observers.length&&R((()=>{for(let g=0;g1e6)throw n=[],new Error}),!1)),g}function d(A){if(!A.fn)return;U(A);const g=t,I=s,B=a;s=t=A,function(A,g,I){let B;try{B=A.fn(g)}catch(g){A.pure&&(A.state=E,A.owned&&A.owned.forEach(U),A.owned=null),H(g)}(!A.updatedAt||A.updatedAt<=I)&&(null!=A.updatedAt&&"observers"in A?F(A,B):A.value=B,A.updatedAt=I)}(A,A.value,B),s=I,t=g}function f(A,g,I,B=E,Q){const C={fn:A,state:B,updatedAt:null,owned:null,sources:null,sourceSlots:null,cleanups:null,value:g,owner:t,context:null,pure:I};return null===t||t!==i&&(t.owned?t.owned.push(C):t.owned=[C]),C}function Y(A){const g=o;if(0===A.state||g)return;if(A.state===e||g)return S(A);if(A.suspense&&y(A.suspense.inFallback))return A.suspense.effects.push(A);const I=[A];for(;(A=A.owner)&&(!A.updatedAt||A.updatedAt=0;B--)if((A=I[B]).state===E||g)d(A);else if(A.state===e||g){const g=n;n=null,R((()=>S(A,I[0])),!1),n=g}}function R(A,g){if(n)return A();let I=!1;g||(n=[]),r?I=!0:r=[],a++;try{const g=A();return function(A){n&&(J(n),n=null);if(A)return;const g=r;r=null,g.length&&R((()=>C(g)),!1)}(I),g}catch(A){I||(r=null),n=null,H(A)}}function J(A){for(let g=0;gA(g||{})))}function v(A){const g="fallback"in A&&{fallback:()=>A.fallback};return h(function(A,g,I={}){let Q=[],C=[],E=[],e=0,i=g.length>1?[]:null;return M((()=>q(E))),()=>{let t,o,s=A()||[];return s[B],y((()=>{let A,g,B,r,a,D,w,h,l,y=s.length;if(0===y)0!==e&&(q(E),E=[],Q=[],C=[],e=0,i&&(i=[])),I.fallback&&(Q=[m],C[0]=c((A=>(E[0]=A,I.fallback()))),e=1);else if(0===e){for(C=new Array(y),o=0;o=D&&h>=D&&Q[w]===s[h];w--,h--)B[h]=C[w],r[h]=E[w],i&&(a[h]=i[w]);for(A=new Map,g=new Array(h+1),o=h;o>=D;o--)l=s[o],t=A.get(l),g[o]=void 0===t?-1:t,A.set(l,o);for(t=D;t<=w;t++)l=Q[t],o=A.get(l),void 0!==o&&-1!==o?(B[o]=C[t],r[o]=E[t],i&&(a[o]=i[t]),o=g[o],A.set(l,o)):E[t]();for(o=D;oA.each),A.children,g||void 0))}function x(A){const g="fallback"in A&&{fallback:()=>A.fallback};return h(function(A,g,I={}){let Q,C=[],E=[],e=[],i=[],t=0;return M((()=>q(e))),()=>{const o=A()||[];return o[B],y((()=>{if(0===o.length)return 0!==t&&(q(e),e=[],C=[],E=[],t=0,i=[]),I.fallback&&(C=[m],E[0]=c((A=>(e[0]=A,I.fallback()))),t=1),E;for(C[0]===m&&(e[0](),e=[],C=[],E=[],t=0),Q=0;Qo[Q])):Q>=C.length&&(E[Q]=c(s));for(;QA.each),A.children,g||void 0))}function j(A){let g=!1;const I=A.keyed,B=h((()=>A.when),void 0,{equals:(A,I)=>g?A===I:!A==!I});return h((()=>{const Q=B();if(Q){const B=A.children,C="function"==typeof B&&B.length>0;return g=I||C,C?y((()=>B(Q))):B}return A.fallback}),void 0,void 0)}function T(A){let g=!1,I=!1;const B=N((()=>A.children)),Q=h((()=>{let A=B();Array.isArray(A)||(A=[A]);for(let g=0;gA[0]===I[0]&&(g?A[1]===I[1]:!A[1]==!I[1])&&A[2]===I[2]});return h((()=>{const[B,C,E]=Q();if(B<0)return A.fallback;const e=E.children,i="function"==typeof e&&e.length>0;return g=I||i,i?y((()=>e(C))):e}),void 0,void 0)}function Z(A){return A}const W="_$DX_DELEGATE";function O(A,g,I,B={}){let Q;return c((B=>{Q=B,g===document?A():AA(g,A(),g.firstChild?null:void 0,I)}),B.owner),()=>{Q(),g.textContent=""}}function X(A,g,I){const B=document.createElement("template");B.innerHTML=A;let Q=B.content.firstChild;return I&&(Q=Q.firstChild),Q}function z(A,g=window.document){const I=g[W]||(g[W]=new Set);for(let B=0,Q=A.length;BB.call(A,I[1],g))}else A.addEventListener(g,I)}function _(A,g,I){if(!g)return I?function(A,g,I){null==I?A.removeAttribute(g):A.setAttribute(g,I)}(A,"style"):g;const B=A.style;if("string"==typeof g)return B.cssText=g;let Q,C;for(C in"string"==typeof I&&(B.cssText=I=void 0),I||(I={}),g||(g={}),I)null==g[C]&&B.removeProperty(C),delete I[C];for(C in g)Q=g[C],Q!==I[C]&&(B.setProperty(C,Q),I[C]=Q);return I}function $(A,g,I){return y((()=>A(g,I)))}function AA(A,g,I,B){if(void 0===I||B||(B=[]),"function"!=typeof g)return IA(A,g,B,I);w((B=>IA(A,g(),B,I)),B)}function gA(A){const I=`$$${A.type}`;let B=A.composedPath&&A.composedPath()[0]||A.target;for(A.target!==B&&Object.defineProperty(A,"target",{configurable:!0,value:B}),Object.defineProperty(A,"currentTarget",{configurable:!0,get:()=>B||document}),g.registry&&!g.done&&(g.done=!0,document.querySelectorAll("[id^=pl-]").forEach((g=>{for(;g&&8!==g.nodeType&&g.nodeValue!=="pl-"+A;){let A=g.nextSibling;g.remove(),g=A}g&&g.remove()})));B;){const g=B[I];if(g&&!B.disabled){const Q=B[`${I}Data`];if(void 0!==Q?g.call(B,Q,A):g.call(B,A),A.cancelBubble)return}B=B._$host||B.parentNode||B.host}}function IA(A,I,B,Q,C){for(g.context&&!B&&(B=[...A.childNodes]);"function"==typeof B;)B=B();if(I===B)return B;const E=typeof I,e=void 0!==Q;if(A=e&&B[0]&&B[0].parentNode||A,"string"===E||"number"===E){if(g.context)return B;if("number"===E&&(I=I.toString()),e){let g=B[0];g&&3===g.nodeType?g.data=I:g=document.createTextNode(I),B=CA(A,B,Q,g)}else B=""!==B&&"string"==typeof B?A.firstChild.data=I:A.textContent=I}else if(null==I||"boolean"===E){if(g.context)return B;B=CA(A,B,Q)}else{if("function"===E)return w((()=>{let g=I();for(;"function"==typeof g;)g=g();B=IA(A,g,B,Q)})),()=>B;if(Array.isArray(I)){const E=[],i=B&&Array.isArray(B);if(BA(E,I,B,C))return w((()=>B=IA(A,E,B,Q,!0))),()=>B;if(g.context){if(!E.length)return B;for(let A=0;AB-e){const Q=g[E];for(;e=0;C--){const E=g[C];if(Q!==E){const g=E.parentNode===A;B||C?g&&E.remove():g?A.replaceChild(Q,E):A.insertBefore(Q,I)}else B=!0}}else A.insertBefore(Q,I);return[Q]}let EA;const eA=new Array(128).fill(void 0);function iA(A){return eA[A]}eA.push(void 0,null,!0,!1);let tA=eA.length;function oA(A){const g=iA(A);return function(A){A<132||(eA[A]=tA,tA=A)}(A),g}const sA=new TextDecoder("utf-8",{ignoreBOM:!0,fatal:!0});sA.decode();let nA=null;function rA(){return null!==nA&&0!==nA.byteLength||(nA=new Uint8Array(EA.memory.buffer)),nA}function aA(A,g){return sA.decode(rA().subarray(A,A+g))}function cA(A){tA===eA.length&&eA.push(eA.length+1);const g=tA;return tA=eA[g],eA[g]=A,g}function DA(A){const g=typeof A;if("number"==g||"boolean"==g||null==A)return`${A}`;if("string"==g)return`"${A}"`;if("symbol"==g){const g=A.description;return null==g?"Symbol":`Symbol(${g})`}if("function"==g){const g=A.name;return"string"==typeof g&&g.length>0?`Function(${g})`:"Function"}if(Array.isArray(A)){const g=A.length;let I="[";g>0&&(I+=DA(A[0]));for(let B=1;B1))return toString.call(A);if(B=I[1],"Object"==B)try{return"Object("+JSON.stringify(A)+")"}catch(A){return"Object"}return A instanceof Error?`${A.name}: ${A.message}\n${A.stack}`:B}let wA=0;const hA=new TextEncoder("utf-8"),lA="function"==typeof hA.encodeInto?function(A,g){return hA.encodeInto(A,g)}:function(A,g){const I=hA.encode(A);return g.set(I),{read:A.length,written:I.length}};function yA(A,g,I){if(void 0===I){const I=hA.encode(A),B=g(I.length);return rA().subarray(B,B+I.length).set(I),wA=I.length,B}let B=A.length,Q=g(B);const C=rA();let E=0;for(;E127)break;C[Q+E]=g}if(E!==B){0!==E&&(A=A.slice(E)),Q=I(Q,B,B=E+3*A.length);const g=rA().subarray(Q+E,Q+B);E+=lA(A,g).written}return wA=E,Q}let GA=null;function MA(){return null!==GA&&0!==GA.byteLength||(GA=new Int32Array(EA.memory.buffer)),GA}let kA=null;function NA(A,g){return(null!==kA&&0!==kA.byteLength||(kA=new Uint32Array(EA.memory.buffer)),kA).subarray(A/4,A/4+g)}class uA{static __wrap(A){const g=Object.create(uA.prototype);return g.ptr=A,g}__destroy_into_raw(){const A=this.ptr;return this.ptr=0,A}free(){const A=this.__destroy_into_raw();EA.__wbg_vtwrapper_free(A)}feed(A){const g=yA(A,EA.__wbindgen_malloc,EA.__wbindgen_realloc),I=wA;return oA(EA.vtwrapper_feed(this.ptr,g,I))}inspect(){try{const I=EA.__wbindgen_add_to_stack_pointer(-16);EA.vtwrapper_inspect(I,this.ptr);var A=MA()[I/4+0],g=MA()[I/4+1];return aA(A,g)}finally{EA.__wbindgen_add_to_stack_pointer(16),EA.__wbindgen_free(A,g)}}get_size(){try{const B=EA.__wbindgen_add_to_stack_pointer(-16);EA.vtwrapper_get_size(B,this.ptr);var A=MA()[B/4+0],g=MA()[B/4+1],I=NA(A,g).slice();return EA.__wbindgen_free(A,4*g),I}finally{EA.__wbindgen_add_to_stack_pointer(16)}}get_line(A){return oA(EA.vtwrapper_get_line(this.ptr,A))}get_cursor(){return oA(EA.vtwrapper_get_cursor(this.ptr))}}function FA(){const A={wbg:{}};return A.wbg.__wbindgen_object_drop_ref=function(A){oA(A)},A.wbg.__wbindgen_error_new=function(A,g){return cA(new Error(aA(A,g)))},A.wbg.__wbindgen_number_new=function(A){return cA(A)},A.wbg.__wbindgen_bigint_from_u64=function(A){return cA(BigInt.asUintN(64,A))},A.wbg.__wbindgen_string_new=function(A,g){return cA(aA(A,g))},A.wbg.__wbg_set_20cbc34131e76824=function(A,g,I){iA(A)[oA(g)]=oA(I)},A.wbg.__wbg_new_b525de17f44a8943=function(){return cA(new Array)},A.wbg.__wbg_new_f841cc6f2098f4b5=function(){return cA(new Map)},A.wbg.__wbg_new_f9876326328f45ed=function(){return cA(new Object)},A.wbg.__wbindgen_is_string=function(A){return"string"==typeof iA(A)},A.wbg.__wbg_set_17224bc548dd1d7b=function(A,g,I){iA(A)[g>>>0]=oA(I)},A.wbg.__wbg_set_388c4c6422704173=function(A,g,I){return cA(iA(A).set(iA(g),iA(I)))},A.wbg.__wbindgen_debug_string=function(A,g){const I=yA(DA(iA(g)),EA.__wbindgen_malloc,EA.__wbindgen_realloc),B=wA;MA()[A/4+1]=B,MA()[A/4+0]=I},A.wbg.__wbindgen_throw=function(A,g){throw new Error(aA(A,g))},A}function dA(A,g){return EA=A.exports,fA.__wbindgen_wasm_module=g,GA=null,kA=null,nA=null,EA}async function fA(A){const g=FA();("string"==typeof A||"function"==typeof Request&&A instanceof Request||"function"==typeof URL&&A instanceof URL)&&(A=fetch(A));const{instance:I,module:B}=await async function(A,g){if("function"==typeof Response&&A instanceof Response){if("function"==typeof WebAssembly.instantiateStreaming)try{return await WebAssembly.instantiateStreaming(A,g)}catch(g){if("application/wasm"==A.headers.get("Content-Type"))throw g;console.warn("`WebAssembly.instantiateStreaming` failed because your server does not serve wasm with `application/wasm` MIME type. Falling back to `WebAssembly.instantiate` which is slower. Original error:\n",g)}const I=await A.arrayBuffer();return await WebAssembly.instantiate(I,g)}{const I=await WebAssembly.instantiate(A,g);return I instanceof WebAssembly.Instance?{instance:I,module:A}:I}}(await A,g);return dA(I,B)}var YA=Object.freeze({__proto__:null,VtWrapper:uA,create:function(A,g,I,B){const Q=EA.create(A,g,I,B);return uA.__wrap(Q)},default:fA,initSync:function(A){const g=FA();return A instanceof WebAssembly.Module||(A=new WebAssembly.Module(A)),dA(new WebAssembly.Instance(A,g),A)}});const RA=[62,0,0,0,63,52,53,54,55,56,57,58,59,60,61,0,0,0,0,0,0,0,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,0,0,0,0,0,0,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51];function JA(A){return RA[A-43]}const pA=function(A){let g,I=A.endsWith("==")?2:A.endsWith("=")?1:0,B=A.length,Q=new Uint8Array(B/4*3);for(let I=0,C=0;I>16,Q[C+1]=g>>8&255,Q[C+2]=255&g;return Q.subarray(0,Q.length-I)}("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CDcDACACQUBrJAAPCxDhAQALEOIBAAvKAQECfwJAAkAgACgCCCIFIAFPBEAgACgCACABQQR0aiEAAkAgBSABayIEIAJPBEAgBCACayIEIAAgBEEEdGogAhASDAELQfyfwABBIUGgoMAAEIkBAAsgASACaiIEIAJJDQEgBCAFSw0CIAIEQCACQQR0IQIDQCAAIAMpAgA3AgAgAEEIaiADQQhqKQIANwIAIABBEGohACACQRBrIgINAAsLDwsgASAFQfidwAAQWQALIAEgBEGInsAAEFsACyAEIAVBiJ7AABBaAAuWAQEDfwJ/IAJFBEBBACEDQQEMAQsgAygCACEGQQAhAyACIQQCQANAAkBBfyABIAJBAXYgA2oiAkECdGooAgAiBSAGRyAFIAZJGyIFQQFGBEAgAiEEDAELIAVB/wFxQf8BRw0CIAJBAWohAwsgBCADayECIAMgBEkNAAtBAQwBCyACIQNBAAshBCAAIAM2AgQgACAENgIAC5IBAQN/IwBBgAFrIgMkACAALQAAIQJBACEAA0AgACADakH/AGogAkEPcSIEQTBBNyAEQQpJG2o6AAAgAEEBayEAIAJB/wFxIgRBBHYhAiAEQQ9LDQALIABBgAFqIgJBgQFPBEAgAkGAAUGsrcAAEFkACyABQbytwABBAiAAIANqQYABakEAIABrEBUgA0GAAWokAAuTAQEDfyMAQYABayIDJAAgAC0AACECQQAhAANAIAAgA2pB/wBqIAJBD3EiBEEwQdcAIARBCkkbajoAACAAQQFrIQAgAkH/AXEiBEEEdiECIARBD0sNAAsgAEGAAWoiAkGBAU8EQCACQYABQaytwAAQWQALIAFBvK3AAEECIAAgA2pBgAFqQQAgAGsQFSADQYABaiQAC4kBAQN/IwBBgAFrIgMkACAAKAIAIQADQCACIANqQf8AaiAAQQ9xIgRBMEHXACAEQQpJG2o6AAAgAkEBayECIABBD0sgAEEEdiEADQALIAJBgAFqIgBBgQFPBEAgAEGAAUGsrcAAEFkACyABQbytwABBAiACIANqQYABakEAIAJrEBUgA0GAAWokAAuIAQEDfyMAQYABayIDJAAgACgCACEAA0AgAiADakH/AGogAEEPcSIEQTBBNyAEQQpJG2o6AAAgAkEBayECIABBD0sgAEEEdiEADQALIAJBgAFqIgBB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IAQoAgAQDwsgAyACKQMQNwIAIANBGGogAkEQaiIFQRhqKQMANwIAIANBEGogBUEQaikDADcCACAEIAVBCGopAwA3AgAgA0EoaiIFEH0gA0EgaiEEIANBLGooAgAEQCAFKAIAEA8LIAQgAikDMDcCACAEQRhqIAJBMGoiBUEYaikDADcCACAEQRBqIAVBEGopAwA3AgAgBEEIaiAFQQhqIgQpAwA3AgAgA0EAOgC0ASAFIAMoApQBED0gA0H8AGohBSADQYABaigCAARAIAUoAgAQDwsgBSACKQMwNwIAIAVBCGogBCgCADYCACADQbIBakEAOwEAIANBrgFqQQI6AAAgA0ECOgCqASADQdAAakEBOgAAIANCADcCSCADQQA7AagBIANBADoAuQEgA0GAgAQ2ALUBIANCADcCnAEgA0H4AGpBgICACDYCACADQfQAakECOgAAIANB8ABqQQI6AAAgA0HsAGpBADYCACADQeQAakKAgIAINwIAIANB4ABqQQI6AAAgA0HcAGpBAjoAACADQgA3AlQgAyADKAKYASIFQQFrNgKkASACQQhqIAUQayAEQQA2AgAgAiACKQMINwMwIAJBMGogBUEBEE8gAkEYaiAEKAIANgIAIAIgAikDMDcDECADQYgBaiEEIANBjAFqKAIABEAgBCgCABAPCyAEIAIpAxA3AgAgBEEIaiACQRhqKAIANgIAIANBADoAuwEgAkHQAGokAAwBCwJAAkAgBEEoaw4CAAECCyADQQA6AKgBDAELIAJBMEYEQCADQQE6AKkBDAELIANBADoAqQELDAQLIAMgAhAlDAMLIAZBADoAGAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkAgBkEUaigCACIERQRAIAJBQGoONgECAxIEBQYfFgcICQoLICAMICANDiAgDxAgESAgICAgHxITIBQVFhcYICAgHh0gICAgHBsaGSALIAYoAgxBACAEGyEEAkACQAJAAkAgAkHsAGsOBQEjIyMDAAsgAkHoAEYNAQwiCyAEKAIAQT9HDSEgBigCCCICBEAgBigCACEFIAJBAXQhBCADQaoBaiECIANB3ABqIQcDQAJAAkAgBS8BACIIQZYITQRAAkACQAJAAkAgCEEGaw4CAQIA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CwsgBCAIRg0BIAIoAgAhCQtBAQwBC0EACyECIAogCTYCBCAKIAI2AgAgBygCDCECIAcoAgghBCADQQA6ALkBIAMgAiADKAKUASICQQFrIgUgBBsiBCAFIAIgBEsbNgJIIAdBEGokAAwYCwJAAkACQAJAIAYoAgBBxJjAACAGKAIIGy8BAA4DAAECAwsgAyADKAJIIANBzABqIgIoAgBBASADIANBqgFqECYgA0GIAWogAigCACADKAKYARBvDAILIAMgAygCSCADQcwAaiICKAIAQQIgAyADQaoBahAmIANBiAFqQQAgAigCAEEBahBvDAELIANBACADKAIYIANBqgFqEDkgA0GIAWpBACADKAKYARBvCwwXCwJAAkACQAJAAkAgBigCAEHEmMAAIAYoAggbLwEADgMAAQIECyADKAIUIQIgAygCSCEEIAMgA0HMAGooAgAiBUGwlMAAEHsiByAEIAIgA0GqAWoQSiAHQQA6AAwMAgsgAygCFCECIAMoAkhBAWohBCADIANBzABqKAIAIgVBoJTAABB7QQAgBCACIAIgBEsbIANBqgFqEEoMAQsgAygCFCECIAMgA0HMAGooAgAiBUGQlMAAEHsiBEEAIAIgA0GqAWoQSiAEQQA6AAwLIANBkAFqKAIAIgIgBUsEQCADKAKIASAFakEBOgAADAELIAUgAkHskMAAEFgACwwWCyADKAKYASADKAKkASICQQFqIAIgA0HMAGooAgAiAkkbIQQgAyACIAQgBigCAEHEmMAAIAYoAggbLwEAIgVBASAFGyADQaoBahBQIANBiAFqIAIgBBBvDBULIAMoApgBIAMoAqQBIgJBAWogAiADQcwAaigCACICSRshBCADIAIgBCAGKAIAQcSYwAAgBigCCBsvAQAiBUEBIAUbIANBqgFqEBwgA0GIAWogAiAEEG8MFAsgAygCSCICIAMoApQBIgRPBEAgA0EAOgC5ASADIARBAWsiAjYCSAsgBigCAEHEmMAAIAYoAggbLwEAIgRBASAEGyIEIAMoAhQgAmsiBSAEIAVJGyEFIANBqgFqIQgCQAJAIAMgA0HMAGooAgAiB0GAlMAAEHsiCSgCCCIEIAJPBEAgCSgCACIKIAJBBHRqIAQgAmsgBRCcASAEIAVrIQIgBCAFSQ0BIAUEQCAKIARBBHRqIQQgCiACQQR0aiEFIAhBCGohAgNAIAVBIDYCACAFIAgpAAA3AAQgBUEMaiACLwAAOwAAIAQgBUEQaiIFRw0ACwsMAgsgAiAEQZiewAAQWQALIAIgBEGonsAAEFkACyAJQQA6AAwCQCADQZABaigCACICIAdLBEAgAygCiAEgB2pBAToAAAwBCyAHIAJB7JDAABBYAAsMEwsgAyAGKAIAQcSYwAAgBigCCBsvAQAiAkEBIAIbEJ4BDBILIAMgBigCAEHEmMAAIAYoAggbLwEAIgJBASACGxCfAQwRCwJAAkACQAJAIAYoAgBBxJjAACAGKAIIGy8BAA4GAAMBAwMCAwsgAygCSCICRQ0CIAIgAygClAFPDQIgA0H8AGogAhCEAQwCCyADQfwAaiADKAJIEIcBDAELIANBhAFqQQA2AgALDBALIAMgAygCSCADQcwAaiICKAIAQQAgBigCAEHEmMAAIAYoAggbLwEAIgRBASAEGyADQaoBahAmIANBkAFqKAIAIgQgAigCACICTQRAIAIgBEHskMAAEFgACyADKAKIASACakEBOgAADA8LIwBBEGsiCyQAIAtBCGohDCADKAJIIRAgA0H8AGoiAigCACEHIAcgAigCCEECdGohAgJAAkACQCAGKAIAQcSYwAAgBigCCBsvAQAiBEEBIAQbIgRBAWsiEUUNAEEBIQoDQCACQQRrIQQgBSIIQQFqIQUCQANAIAQiAkEEaiAHRg0BIAoEQCACQQRrIQQgAigCACAQTw0BCwtBACEKQQEhCSAFIBFHDQEMAgsLIAchAiAIIBFHDQELA0AgAiAHRg0BIAJBBGsiAigCACEEQQEhCiAJDQIgBCAQTw0ACwwBC0EAIQoLIAwgBDYCBCAMIAo2AgAgCygCDCECIAsoAgghBCADQQA6ALkBIAMgAkEAIAQbIgIgAygClAEiBEEBayACIARJGzYCSCALQRBqJAAMDgsgA0EAOgC5ASADQQAgAygCSCAGKAIAQcSYwAAgBigCCBsvAQAiAkEBIAIbaiICIAMoApQBIgRBAWsgAiAESRsgAkEASBs2AkgMDQsgAygCSCICBEAgBigCAEHEmMAAIAYoAggbLwEAIgRBASAEGyEFIAJBAWshBCADQcwAaigCACEHIwBBEGsiAiQAIAJBCGogAxCFAQJAAkAgAigCDCIIIAdLBEAgAigCCCAHQQR0aiIHKAIIIgggBE0NASAHKAIAIAJBEGokACAEQQR0aiECDAILIAcgCEHYisAAEFgACyAEIAhB2IrAABBYAAsgAigCACECA0AgAyACEBggBUEBayIFDQALCwwMCyADQQA6ALkBIAMgAygCSCICIAMoApQBQQFrIgQgAiAESRs2AkggA0HMAGogAygCoAFBACADLQC2ASIEGyICIAYoAgBBxJjAACAGKAIIGy8BACIFQQEgBRtqQQFrIgUgAiACIAVJGyICIAMoAqQBIAMoApgBQQFrIAQbIgQgAiAESRs2AgAMCwsgAyAGEFYMCgsgA0EAOgC5ASADQcwAaiADKAKgAUEAIAMtALYBIgQbIgIgBigCACIFQcSYwAAgBigCCCIHGy8BACIIQQEgCBtqQQFrIgggAiACIAhJGyICIAMoAqQBIAMoApgBQQFrIAQbIgQgAiAESRs2AgAgAyAFQQJqQcSYwAAgB0EBSxsvAQAiAkEBIAIbQQFrIgQgAygClAEiBUEBayICIAQgBUkbIgQgAiACIARLGzYCSAwJCwJAAkACQCAGKAIAQcSYwAAgBigCCBsvAQAOBAACAgECCyADQfwAaiADKAJIEIcBDAELIANBhAFqQQA2AgALDAgLIAYoAggiAkUNByAGKAIAIQQgAkEBdCECA0ACQAJAIAQvAQAiBUEERwRAIAVBFEYNAQwCCyADQQE6ALUBDAELIANBAToAuAELIARBAmohBCACQQJrIgINAAsMBwsgA0EAOgC5ASADIAMpAlQ3AkggAyADQdwAaikBADcBqgEgA0GyAWogA0HkAGovAQA7AQAgAyADQeYAai8BADsBtgEMBgsCQCADLQC6AUUNACAGKAIAIgJBxJjAACAGKAIIIgQbLwEAQQhHDQAgAkECakHEmMAAIARBAUsbLwEAIgUgAygCmAEiByAFGyEJIAJBBGpBxJjAACAEQQJLGy8BACICIAMoApQBIgUgAhshCAJAAkACQAJAQX8gBSAIRyAFIAhLG0H/AXEOAgMBAAsCQCADQYQBaigCACICRQRAQQAhBQwBCyADKAJ8IQtBACEFIAIhBANAIAsgAkEBdiAFaiICQQJ0aigCACAISSEKIAQgAiAKGyIEIAJBAWogBSAKGyIFayECIAQgBUsNAAsLIAMgBTYChAEMAQsgA0H8AGohBEEAIQIgBUF4cUEI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QQhqKAIANgIAIAYgASkCADcDICAEKAIAIQUgBCgCBCELA0ACQAJAIAUgC0cEQCAEIAVBAWoiBzYCACAFLQAAIAQgBCgCCCIQQQFqNgIIIAchBUUNAyACKAIIIgcgAigCBEcNASACIAcQdQwBCwwBCyACIAdBAWo2AgggAigCACAHQQJ0aiAQNgIADAELCyANQQhqIAooAgA2AgAgDSAGKQMQNwIADAELIA1BADYCCCANQgQ3AgALIAZBMGokACANIAMtALsBOgAMIAgEQCAJQQAgCBDoAQsgA0EAOgC7ASABQRBqJAAjAEFAaiIEJAAgBEEAOwEYIARBADoAGiAEQTBqIARBGGoQtwECfwJAAkACfwJAIAQoAjAEQCAEQSBqIgVBCGogBEE4aigCADYCACAEIAQpAzA3AyAgBEEQaiEJIwBBEGsiByQAIAUoAgghECAHQQhqIQogBSgCACEDIwBBMGsiASQAIA0oAgAhAiABQSBqIAMgDSgCCCIDELYBAn8CQAJAIAEoAiAEQCABQRhqIAFBKGooAgA2AgAgASABKQMgNwMQIANBAnQhCANAIAhFDQMgCEEEayEIIAEgAjYCICACQQRqIQIgAUEIaiELIwBBEGsiAyQAIAFBEGoiBigCCCERIANBCGogBigCACABQSBqKAIANQIAEEYgAygCDCEMIAMoAggiE0UEQCAGQQRqIBEgDBDQASAGIAYoAghBAWo2AggLIAsgEzYCACALIAw2AgQgA0EQaiQAIAEoAghFDQALIAEoAgwhAiABKAIUIgNBhAFJDQEgAxAADAELIAEoAiQhAgtBAQwBCyABQSBqIgJBCGogAUEYaigCADYCACABIAEpAxA3AyAgASACKAIENgIEIAFBADYCACABKAIEIQIgASgCAAshAyAKIAI2AgQgCiADNgIAIAFBMGokACAHKAIMIQEgBygCCCICRQRAIAVBBGogECABENABIAUgBSgCCEEBajYCCAsgCSACNgIAIAkgATYCBCAHQRBqJAAgBCgCEEUNASAEKAIUDAILIAQoAjQhAQwDCyAEQQhqIQUjAEEQayIBJAAgBEEgaiICKAIIIQMgAigCABogAUEIaiIHQYIBQYMBIA1BDGotAAAbNgIEIAdBADYCACABKAIMIQcgASgCCCINRQRAIAJBBGogAyAHENABIAIgAigCCEEB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akEKNgIAIARBOGoiCEEMakEKNgIAIARBBDYCJCAEQcyEwAA2AiAgBCADQQNqNgJIIAQgA0ECajYCQCAEQQo2AjwgBCADQQFqNgI4IAQgCDYCKCAEQRBqIgggChAaIARBCGogByAEKAIQIAQoAhgQvQEgBCgCDCEDIAQoAgghByAIELABCyAJIAc2AgAgCSADNgIEIARB0ABqJAAgBSgCDCEDAkACQCAFKAIIRQRAIAUgAzYCGCACKAIARQRAIAJBBGogBUEUaiAFQRhqEMUBIgJBhAFPBEAgAhAACyAFKAIYIgJBhAFPBEAgAhAACyAFKAIUIgJBhAFJDQMgAhAADAMLIAUgATYCHCAFQRxqENEBIQEgBSgCHCEEIAENARA+IQEgBEGEAU8EQCAEEAALIANBhAFJDQUgAxAADAULIAFBhAFJDQMgARAADAMLIAJBBGogBCADEM8BC0EADAMLQfiCwABBFRDjAQALIAMhAQtBAQshAiAGIAE2AgQgBiACNgIAIAVBIGokACAGKAIAIQIgBigCBAshASAAIAI2AgAgACABNgIEIAZBEGokAAuWAwEDfyMAQRBrIgQkACAEQQhqIAEgAiADEFUgACIGAn8gBCgCCARAIAQoAgwhA0EBDAELIwBBIGsiAyQAIAEoAgghACABQQA2AggCfwJAAkAgAARAIAMgAUEMaigCACIANgIUIAEoAhAaIANBCGoiAkGCAUGDAUGZhMAALQAAGzYCBCACQQA2AgAgAygCDCECAkACQCADKAIIRQRAIAMgAjYCGCABKAIARQRAIAFBBGogA0EUaiADQRhqEMUBIgFBhAFPBEAgARAACyADKAIYIgFBhAFPBEAgARAACyADKAIUIgFBhAFJDQMgARAADAMLIAMgADYCHCADQRxqENEBIQAgAygCHCEFIAANARA+IQAgBUGEAU8EQCAFEAALIAJBhAFJDQUgAhAADAULIABBhAFJDQMgABAADAMLIAFBBGogBSACEM8BC0EADAMLQfiCwABBFRDjAQALIAIhAAtBAQshASAEIAA2AgQgBCABNgIAIANBIGokACAEKAIEIQMgBCgCAAs2AgAgBiADNgIEIARBEGokAAtbAQJ/AkAgAUUEQEEBIQIMAQsgAUEATiIDBEBBtcTAAC0AABogASADEMcBIgINASADIAFB2MTAACgCACIA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EDcAC0HwpMAAQStBvKbAABCJAQALQfCkwABBK0GspsAAEIkBAAszAQF/IwBBEGsiAiQAIAIgACgCADYCDCABQciawABBDSACQQxqQdiawAAQMSACQRBqJAALMAEBfyMAQRBrIgIkACACIAA2AgwgAUGohcAAQQUgAkEMakGwhcAAEDEgAkEQaiQACzABAX8jAEEQayICJAAgAiAANgIMIAFBjJLAAEEKIAJBDGpBmJLAABAxIAJBEGokAAswAQF/IwBBEGsiAiQAIAIgADYCDCABQa+awABBBiACQQxqQbiawAAQMSACQRBqJAALMAEBfyMAQRBrIgIkACACIAA2AgwgAUGwocAAQQQgAkEMakG0ocAAEDEgAkEQaiQACzwAIAAoAgAhACABLQAcQRBxQQR2RQRAIAEtABxBIHFBBXZFBEAgACABENQBDwsgACABEEUPCyAAIAEQRAvTAgEDfyAAKAIAIQAgAS0AHEEQcUEEdkUEQCABLQAcQSBxQQV2RQRAIAAzAQAgARAgDwsjAEGAAWsiAyQAIAAvAQAhAkEAIQADQCAAIANqQf8AakEwQTcgAkEPcSIEQQpJGyAEajoAACAAQQFrIQAgAkH//wNxIgRBBHYhAiAEQQ9LDQALIABBgAFqIgJBgQFPBEAgAkGAAUGsrcAAEFkACyABQbytwABBAiAAIANqQYABakEAIABrEBUgA0GAAWokAA8LIwBBgAFrIgMkACAALwEAIQJBACEAA0AgACADakH/AGpBMEHXACACQQ9xIgRBCkkbIARqOgAAIABBAWshACACQf//A3EiBEEEdiECIARBD0sNAAsgAEGAAWoiAkGBAU8EQCACQYABQaytwAAQWQALIAFBvK3AAEECIAAgA2pBgAFqQQAgAGsQFSADQYABaiQACzwAIAAoAgAhACABLQAcQRBxQQR2RQRAIAEtABxBIHFBBXZFBEAgACABENUBDwsgACABEEIPCyAAIAEQQwssACABIAJPBEAgAiAAIAJBBHRqIAEgAmsQEg8LQdibwABBI0HInMAAEIkBAAssACABIAJPBEAgAiAAIAJBBHRqIAEgAmsQEg8LQfyewABBI0Hsn8AAEIkBAAsfAQF/IABBCGoiARB9IABBDGooAgAEQCABKAIAEA8LCy8BAn8gACAAKAKgASICIAAoAqQBQQFqIgMgASAAQaoBahAcIABBiAFqIAIgAxBvCy8BAn8gACAAKAKgASICIAAoAqQBQQFqIgMgASAAQaoBahBQIABBiAFqIAIgAxBvCzUBAX8gASgCFEHrqsAAQQEgAUEYaigCACgCDBEBACECIABBADoABSAAIAI6AAQgACABNgIACzYAAkAgAS0AHEEQcUEEdkUEQCABLQAcQSBxQQV2DQEgACABENUBDwsgACABEEMPCyAAIAEQQgs2AAJAIAEtABxBEHFBBHZFBEAgAS0AHEEgcUEFdg0BIAAgARDUAQ8LIAAgARBEDwsgACABEEULHgACQCAALQAMQQJGDQAgACgCBEUNACAAKAIAEA8LCyABAX8CQCAAKAIEIgFFDQAgAEEIaigCAEUNACABEA8LCyMAAkAgAUH8////B00EQCAAIAFBBCACELwBIgANAQsACyAACyUAIABFBEBByIbAAEEyEOMBAAsgACACIAMgBCAFIAEoAhARCAALFQAgABB9IAAoAgQEQCAAKAIAEA8LCyMAIABFBEBByIbAAEEyEOMBAAsgACACIAMgBCABKAIQEQUACyMAIABFBEBByIbAAEEyEOMBAAsgACACIAMgBCABKAIQEQsACyMAIABFBEBByIbAAEEyEOMBAAsgACACIAMgBCABKAIQERgACyMAIABFBEBByIbAAEEyEOMBAAsgACACIAMgBCABKAIQERoACyMAIABFBEBByIbAAEEyEOMBAAsgACACIAMgBCABKAIQERwACzMAIAEoAhQgAC0AAEECdCIAQfCHwABqKAIAIABB5IfAAGooAgAgAUEYaigCACgCDBEBAAszACABKAIUIAAtAABBAnQiAEGgm8AAaigCACAAQeiawABqKAIAIAFBGGooAgAoAgwRAQALIQAgAEUEQEHIhsAAQTIQ4wEACyAAIAIgAyABKAIQEQMACxEAIAAoAgQEQCAAKAIAEA8LCzEAIAEoAhRBwKLAAEHHosAAIAAoAgAtAAAiABtBB0EFIAAbIAFBGGooAgAoAgwRAQALFAAgAEEEaigCAARAIAAoAgAQDwsLIgAgAC0AAEUEQCABQcSvwABBBRAQDwsgAUHAr8AAQQQQEAsfACAARQRAQciGwABBMhDjAQALIAAgAiABKAIQEQAACy4AIAEoAhRB2I/AAEHhj8AAIAAtAAAiABtBCUEHIAAbIAFB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AEEQaiQAC40BAQJ/IAAoAgAiACgCACECIAAoAgghAyMAQRBrIgAkACAAIAEQoAEgAwRAIANBAXQhAQNAIAAgAjYCDCAAIABBDGpBrIjAABDWASACQQJqIQIgAUECayIBDQALCyAALQAEBH9BAQUgACgCACIBKAIUQY6twABBASABQRhqKAIAKAIMEQEACyAAQRBqJAALCwAgAQRAIAAQDwsLEwAgACgCACABIAEgAmoQgAFBAAsTACABKAIUIAFBGGooAgAgABAWCxMAIAAoAgAgASgCACACKAIAEAsLFAAgACgCACABIAAoAgQoAgwRAAALGQACfyABQQlPBEAgASAAEBsMAQsgABAOCwuIAQECfyAAKAIAIQIgACgCCCEDIwBBEGsiACQAIAAgARCgASADBEAgA0EEdCEBA0AgACACNgIMIAAgAEEMakHciMAAENYBIAJBEGohAiABQRBrIgENAAsLIAAtAAQEf0EBBSAAKAIAIgEoAhRBjq3AAEEBIAFBGGooAgAoAgwRAQALIABBEGokAAuIAQECfyAAKAIAIQIgACgCCCEDIwBBEGsiACQAIAAgARCgASADBEAgA0EEdCEBA0AgACACNgIMIAAgAEEMakGMiMAAENYBIAJBEGohAiABQRBrIgENAAsLIAAtAAQEf0EBBSAAKAIAIgEoAhRBjq3AAEEBIAFBGGooAgAoAgwRAQALIABBEGokAAsRACAAKAIAIAAoAgggARDmAQsOACAAIAEgASACahCAAQsTACAAQdymwAA2AgQgACABNgIACxAAIAEgACgCACAAKAIEEBALDQAgACABIAIQywFBAAsNACAAKAIAIAEgAhAFCw0AIAAoAgAgASACEAoLDAAgACgCABAJQQFGC6EEAQV/IAAoAgAhAyMAQRBrIgQkAAJAIAFB/wBNBEAgAygCCCICIAMoAgRGBEAjAEEgayIAJAACQAJAIAJBAWoiAkUNACADQQRqKAIAIgZBAXQiBSACIAIgBUkbIgJBCCACQQhLGyIFQX9zQR92IQICQCAGBEAgACAGNgIYIABBATYCFCAAIAMoAgA2AhAMAQsgAEEANgIUCyAAIAIgBSAAQRBqEDQgACgCBCECIAAoAgBFBEAgAyACNgIAIANBBGogBTYCAAwCCyACQYGAgIB4Rg0BIAJFDQAgAiAAQQhqKAIAQdjE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JAAgA0EXNgIAIANBFzYCBCABKAIUQdCPwABBCCABQRhqKAIAKAIMEQEAIQUgA0EAOgANIAMgBToADCADIAE2AggCfwNAIANBCGogBCgCACAEQQRqKAIAIAJBsK/AABAeIQUgAkEIaiECIARBCGohBCAGQQFrIgYNAAsgAy0ADCICQQBHIAMtAA1FDQAaQQEgAg0AGiAFKAIAIgEtABxBBHFFBEAgASgCFEGHrcAAQQIgAUEYaigCACgCDBEBAAwBCyABKAIUQYatwABBASABQRhqKAIAKAIMEQEACyADQSBqJAAgAEHAAWokAAtyAQJ/QQIhAyMAQRBrIgIkACACIAEQoAEDQCACIAA2AgwgAiACQQxqQcyIwAAQ1gEgAEEBaiEAIANBAWsiAw0ACyACLQAEBH9BAQUgAigCACIAKAIUQY6twABBASAAQRhqKAIAKAIMEQEACyACQRBqJAALDQBBzKLAAEEbEOMBAAsOAEHnosAAQc8AEOMBAAsJACAAIAEQDQALDAAgACgCACABELMBCwsAIAAoAgAgARAkCwoAIAIgACABEBALwAIBA38gACgCACEAIwBBgAFrIgQkAAJAAkACQAJAIAEoAhwiAkEQcUUEQCACQSBxDQEgADUCACABECAhAAwECyAAKAIAIQBBACECA0AgAiAEakH/AGpBMEHXACAAQQ9xIgNBCkkbIANqOgAAIAJBAWshAiAAQQ9LIABBBHYhAA0ACyACQYABaiIAQYEBTw0BIAFBvK3AAEECIAIgBGpBgAFqQQAgAmsQFSEADAMLIAAoAgAhAEEAIQIDQCACIARqQf8AakEwQTcgAEEPcSIDQQpJGyADajoAACACQQFrIQIgAEEPSyAAQQR2IQANAAsgAkGAAWoiAEGBAU8NASABQbytwABBAiACIARqQYABakEAIAJrEBUhAAwCCyAAQYABQaytwAAQWQALIABBgAFBrK3AABBZAAsgBEGAAWokACAAC5wBAQJ/IAJBD0sEQEEAIABrQQNxIgMgAGohBCADBEADQCAAIAE6AAAgBCAAQQFqIgBLDQALCyACIANrIgJBfHEiAyAEaiEAIANBAEoEQCABQf8BcUGBgoQIbCEDA0AgBCADNgIAIARBBGoiBCAASQ0ACwsgAkEDcSECCyACBEAgACACaiECA0AgACABOgAAIAIgAEEBaiIA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AAAAL3J1c3RjL2ViMjYyOTZiNTU2Y2VmMTBmYjcxM2EzOGYzZDE2Yjk4ODYwODBmMjYvbGlicmFyeS9hbGxvYy9zcmMvcmF3X3ZlYy5yc+wCEABMAAAArgEAAAkAAABjbG9zdXJlIGludm9rZWQgcmVjdXJzaXZlbHkgb3IgYWZ0ZXIgYmVpbmcgZHJvcHBlZFBlbmZvcmVncm91bmQAGgAAAAQAAAABAAAAGwAAAGJhY2tncm91bmRpbnRlbnNpdHkAGgAAAAEAAAABAAAAHAAAAGF0dHJzAAAAHQAAAAQAAAAEAAAAHgAAAEZhaW50Qm9sZE5vcm1hbAAGAAAABAAAAAUAAADdAxAA2QMQANQDEAAfAAAABAAAAAQAAAAgAAAAHwAAAAQAAAAEAAAAIQAAAB8AAAAEAAAABAAAACIAAAAfAAAABAAAAAQAAAAjAAAAHwAAAAQAAAAEAAAAJAAAAB8AAAAEAAAABAAAACUAAAAfAAAABAAAAAQAAAAmAAAAUkdCcicAAAABAAAAAQAAACgAAABnYgAAHwAAAAQAAAAEAAAAHgAAAEN1cnNvcmNvbAAAAB8AAAAEAAAABAAAACkAAAByb3d2aXNpYmxlUkdCAAAAKgAAAAQAAAAEAAAAKwAAAEluZGV4ZWQAKgAAAAQAAAAEAAAAHgAAAC9ob21lL21hcmNpbi8uY2FyZ28vZ2l0L2NoZWNrb3V0cy9hdnQtNjgzMzk3ODhiYTdkNjczZS8yOGFlZDJiL3NyYy90ZXJtaW5hbC5ycwAA6AQQAE4AAABoAQAACgAAAOgEEABOAAAAnwEAABEAAADoBBAATgAAAN4CAAAYAAAAY29sc3Jvd3NidWZmZXJvdGhlcl9idWZmZXJhY3RpdmVfYnVmZmVyX3R5cGVzY3JvbGxiYWNrX2xpbWl0Y3Vyc29ycGVuY2hhcnNldHNhY3RpdmVfY2hhcnNldHRhYnNpbnNlcnRfbW9kZW9yaWdpbl9tb2RlYXV0b193cmFwX21vZGVuZXdfbGluZV9tb2RlbmV4dF9wcmludF93cmFwc3RvcF9tYXJnaW5ib3R0b21fbWFyZ2luc2F2ZWRfY3R4YWx0ZXJuYXRlX3NhdmVkX2N0eGRpcnR5X2xpbmVzcmVzaXphYmxlcmVzaXplZAAAaAUQAAQAAABsBRAABAAAAHAFEAAG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");function SA(A){return"number"==typeof A?A:"string"==typeof A?A.split(":").reverse().map(parseFloat).reduce(((A,g,I)=>A+g*Math.pow(60,I))):void 0}class LA{constructor(){let A=arguments.length>0&&void 0!==arguments[0]?arguments[0]:1;this.speed=A,this.startTime=performance.now()}getTime(){return this.speed*(performance.now()-this.startTime)/1e3}setTime(A){this.startTime=performance.now()-A/this.speed*1e3}}class UA{constructor(){}getTime(A){}setTime(A){}}const HA=(async()=>(await fA(pA),YA))();class KA{constructor(A){this.core=A,this.driver=A.driver}onEnter(A){}init(){}play(){}pause(){}togglePlay(){}seek(A){return!1}step(){}stop(){this.driver.stop()}}class mA extends KA{async init(){try{return await this.core.initializeDriver(),this.core.setState("stopped")}catch(A){throw this.core.setState("errored"),A}}async play(){this.core.dispatchEvent("play");const A=await this.init();return await A.doPlay()}togglePlay(){return this.play()}async seek(A){const g=await this.init();return await g.seek(A)}async step(){const A=await this.init();return await A.step()}stop(){}}class qA extends KA{onEnter(A){this.core.dispatchEvent("stopped"),"paused"===A.reason?this.core.dispatchEvent("pause"):"ended"===A.reason&&this.core.dispatchEvent("ended")}play(){return this.core.dispatchEvent("play"),this.doPlay()}async doPlay(){const A=await this.driver.play();!0===A?this.core.setState("playing"):"function"==typeof A&&(this.core.setState("playing"),this.driver.stop=A)}togglePlay(){return this.play()}seek(A){return this.driver.seek(A)}step(){this.driver.step()}}class bA extends KA{onEnter(){this.core.dispatchEvent("playing")}pause(){!0===this.driver.pause()&&this.core.setState("stopped",{reason:"paused"})}togglePlay(){return this.pause()}seek(A){return this.driver.seek(A)}}class vA extends KA{onEnter(){this.core.dispatchEvent("loading")}}class xA extends KA{onEnter(){this.core.dispatchEvent("offline")}}class jA extends KA{onEnter(){this.core.dispatchEvent("errored")}}class TA{constructor(A,g){this.logger=g.logger,this.state=new mA(this),this.stateName="uninitialized",this.driver=null,this.driverFn=A,this.changedLines=new Set,this.cursor=void 0,this.duration=void 0,this.cols=g.cols,this.rows=g.rows,this.speed=g.speed??1,this.loop=g.loop,this.idleTimeLimit=g.idleTimeLimit,this.preload=g.preload,this.startAt=SA(g.startAt),this.poster=this.parsePoster(g.poster),this.markers=this.normalizeMarkers(g.markers),this.pauseOnMarkers=g.pauseOnMarkers,this.commandQueue=Promise.resolve(),this.eventHandlers=new Map([["marker",[]],["ended",[]],["errored",[]],["init",[]],["input",[]],["loading",[]],["offline",[]],["pause",[]],["play",[]],["playing",[]],["reset",[]],["resize",[]],["seeked",[]],["stopped",[]],["terminalUpdate",[]]])}addEventListener(A,g){this.eventHandlers.get(A).push(g)}dispatchEvent(A){let g=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};for(const I of this.eventHandlers.get(A))I(g)}async init(){this.wasm=await HA;const A=this.feed.bind(this),g=this.now.bind(this),I=this.resetVt.bind(this),B=this.setState.bind(this),Q="npt"===this.poster.type?this.poster.value:void 0;this.driver=this.driverFn({feed:A,onInput:A=>{this.dispatchEvent("input",{data:A})},onMarker:A=>{let{index:g,time:I,label:B}=A;this.dispatchEvent("marker",{index:g,time:I,label:B})},reset:I,now:g,setTimeout:(A,g)=>window.setTimeout(A,g/this.speed),setInterval:(A,g)=>window.setInterval(A,g/this.speed),setState:B,logger:this.logger},{cols:this.cols,rows:this.rows,idleTimeLimit:this.idleTimeLimit,startAt:this.startAt,loop:this.loop,posterTime:Q,markers:this.markers,pauseOnMarkers:this.pauseOnMarkers}),"function"==typeof this.driver&&(this.driver={play:this.driver}),(this.preload||void 0!==Q)&&this.withState((A=>A.init()));const C="text"===this.poster.type?this.renderPoster(this.poster.value):void 0,E={isPausable:!!this.driver.pause,isSeekable:!!this.driver.seek,poster:C};if(void 0===this.driver.init&&(this.driver.init=()=>({})),void 0===this.driver.pause&&(this.driver.pause=()=>{}),void 0===this.driver.seek&&(this.driver.seek=A=>!1),void 0===this.driver.step&&(this.driver.step=()=>{}),void 0===this.driver.stop&&(this.driver.stop=()=>{}),void 0===this.driver.getCurrentTime){const A=this.driver.play;let g=new UA;this.driver.play=()=>(g=new LA(this.speed),A()),this.driver.getCurrentTime=()=>g.getTime()}return E}play(){return this.withState((A=>A.play()))}pause(){return this.withState((A=>A.pause()))}togglePlay(){return this.withState((A=>A.togglePlay()))}seek(A){return this.withState((async g=>{await g.seek(A)&&this.dispatchEvent("seeked")}))}step(){return this.withState((A=>A.step()))}stop(){return this.withState((A=>A.stop()))}withState(A){return this.enqueueCommand((()=>A(this.state)))}enqueueCommand(A){return this.commandQueue=this.commandQueue.then(A),this.commandQueue}getChangedLines(){if(this.changedLines.size>0){const A=new Map,g=this.vt.rows;for(const I of this.changedLines)I1&&void 0!==arguments[1]?arguments[1]:{};if(this.stateName===A)return this.state;if(this.stateName=A,"playing"===A)this.state=new bA(this);else if("stopped"===A)this.state=new qA(this);else if("loading"===A)this.state=new vA(this);else if("offline"===A)this.state=new xA(this);else{if("errored"!==A)throw`invalid state: ${A}`;this.state=new jA(this)}return this.state.onEnter(g),this.state}feed(A){this.doFeed(A),this.dispatchEvent("terminalUpdate")}doFeed(A){const[g,I]=this.vt.feed(A);if(g.forEach((A=>this.changedLines.add(A))),this.cursor=void 0,I){const[A,g]=this.vt.get_size();this.vt.cols=A,this.vt.rows=g,this.logger.debug(`core: vt resize (${A}x${g})`),this.dispatchEvent("resize",{cols:A,rows:g})}}now(){return performance.now()*this.speed}async initializeDriver(){const A=await this.driver.init();this.cols=this.cols??A.cols??80,this.rows=this.rows??A.rows??24,this.duration=this.duration??A.duration,this.markers=this.normalizeMarkers(A.markers)??this.markers??[],this.initializeVt(this.cols,this.rows);const g=void 0!==A.poster?this.renderPoster(A.poster):void 0;this.dispatchEvent("init",{cols:this.cols,rows:this.rows,duration:this.duration,markers:this.markers,poster:g})}resetVt(A,g){let I=arguments.length>2&&void 0!==arguments[2]?arguments[2]:void 0;this.cols=A,this.rows=g,this.cursor=void 0,this.initializeVt(A,g),void 0!==I&&""!==I&&this.doFeed(I),this.dispatchEvent("reset",{cols:A,rows:g})}initializeVt(A,g){this.logger.debug(`core: vt init (${A}x${g})`),this.vt=this.wasm.create(A,g,!0,100),this.vt.cols=A,this.vt.rows=g,this.changedLines.clear();for(let A=0;AB.feed(A)));const Q=B.get_cursor()??!1,C=[];for(let A=0;A"number"==typeof A?[A,""]:A))}}const ZA=Symbol("store-raw"),WA=Symbol("store-node"),OA=Symbol("store-name");function XA(A,g){let B=A[I];if(!B&&(Object.defineProperty(A,I,{value:B=new Proxy(A,gg)}),!Array.isArray(A))){const g=Object.keys(A),I=Object.getOwnPropertyDescriptors(A);for(let Q=0,C=g.length;Q!0,deleteProperty:()=>!0,ownKeys:function(A){return $A(A),Reflect.ownKeys(A)},getOwnPropertyDescriptor:function(A,g){const B=Reflect.getOwnPropertyDescriptor(A,g);return B&&!B.get&&B.configurable&&g!==I&&g!==WA&&g!==OA?(delete B.value,delete B.writable,B.get=()=>A[I][g],B):B}};function Ig(A,g,I,B=!1){if(!B&&A[g]===I)return;const Q=A[g],C=A.length;void 0===I?delete A[g]:A[g]=I;let E,e=PA(A);(E=_A(e,g,Q))&&E.$((()=>I)),Array.isArray(A)&&A.length!==C&&(E=_A(e,"length",C))&&E.$(A.length),(E=e._)&&E.$()}function Bg(A,g){const I=Object.keys(g);for(let B=0;B1){B=g.shift();const C=typeof B,E=Array.isArray(A);if(Array.isArray(B)){for(let Q=0;Q1)return void Qg(A[B],g,[B].concat(I));Q=A[B],I=[B].concat(I)}let C=g[0];"function"==typeof C&&(C=C(Q,I),C===Q)||void 0===B&&null==C||(C=VA(C),void 0===B||zA(Q)&&zA(C)&&!Array.isArray(C)?Bg(Q,C):Ig(A,B,C))}function Cg(...[A,g]){const I=VA(A||{}),B=Array.isArray(I);return[XA(I),function(...A){l((()=>{B&&1===A.length?function(A,g){if("function"==typeof g&&(g=g(A)),g=VA(g),Array.isArray(g)){if(A===g)return;let I=0,B=g.length;for(;I=E&&i>=E&&(C[e]===A[i]||Q&&C[E]&&A[E]&&C[e][Q]===A[i][Q]);e--,i--)n[i]=C[e];if(E>i||E>e){for(I=E;I<=i;I++)Ig(C,I,A[I]);for(;IA.length&&Ig(C,"length",A.length))}for(o=new Array(i+1),I=i;I>=E;I--)t=A[I],s=Q&&t?t[Q]:t,g=r.get(s),o[I]=void 0===g?-1:g,r.set(s,I);for(g=E;g<=e;g++)t=C[g],s=Q&&t?t[Q]:t,I=r.get(s),void 0!==I&&-1!==I&&(n[I]=C[g],I=o[I],r.set(s,I));for(I=E;IA.length&&Ig(C,"length",A.length))}const E=Object.keys(A);for(let g=0,I=E.length;g{if(!zA(A)||!zA(Q))return Q;const g=eg(Q,{[Eg]:A},Eg,I,B);return void 0===g?A:g}}const tg=X("");var og=A=>(()=>{const g=tg.cloneNode(!0);return AA(g,(()=>A.text)),w((I=>{const B=function(A,g){const I=A.get("inverse")?A.has("bg")?A.get("bg"):"bg":A.get("fg"),B=A.get("inverse")?A.has("fg")?A.get("fg"):"fg":A.get("bg"),Q=sg(I,A.get("bold"),"fg-"),C=sg(B,A.get("blink"),"bg-");let E=g??"";Q&&(E+=" "+Q);C&&(E+=" "+C);A.has("bold")&&(E+=" ap-bright");A.has("faint")&&(E+=" ap-faint");A.has("italic")&&(E+=" ap-italic");A.has("underline")&&(E+=" ap-underline");A.has("blink")&&(E+=" ap-blink");return E}(A.attrs,A.extraClass),Q=function(A){const g=A.get("inverse")?A.get("bg"):A.get("fg"),I=A.get("inverse")?A.get("fg"):A.get("bg");let B={};"string"==typeof g&&(B.color=g);"string"==typeof I&&(B["background-color"]=I);return B}(A.attrs);return B!==I._v$&&V(g,I._v$=B),I._v$2=_(g,Q,I._v$2),I}),{_v$:void 0,_v$2:void 0}),g})();function sg(A,g,I){return"number"==typeof A?(g&&A<8&&(A+=8),`${I}${A}`):"fg"==A||"bg"==A?`${I}${A}`:void 0}const ng=X('');var rg=A=>(()=>{const g=ng.cloneNode(!0);return AA(g,b(x,{get each(){return(()=>{if("number"==typeof A.cursor){const g=[];let I=0,B=0;for(;B0&&g.push([Q[0].substring(0,e),Q[1]]),g.push([Q[0][e],C," ap-cursor-a"]),g.push([Q[0][e],E," ap-cursor-b"]),eb(og,{get text(){return A()[0]},get attrs(){return A()[1]},get extraClass(){return A()[2]}})})),w((()=>g.style.setProperty("height",A.height))),g})();const ag=X('
');var cg=A=>{const g=()=>A.lineHeight??1.3333333333,I=h((()=>({width:`${A.cols}ch`,height:g()*A.rows+"em","font-size":100*(A.scale||1)+"%","font-family":A.fontFamily,"line-height":`${g()}em`})));return(()=>{const B=ag.cloneNode(!0),Q=A.ref;return"function"==typeof Q?$(Q,B):A.ref=B,AA(B,b(v,{get each(){return A.lines},children:(I,B)=>b(rg,{get segments(){return I.segments},get cursor(){return h((()=>B()===A.cursor?.[1]))()?A.cursor?.[0]:null},get height(){return`${g()}em`}})})),w((g=>{const Q=!(!A.blink&&!A.cursorHold),C=!!A.blink,E=I();return Q!==g._v$&&B.classList.toggle("ap-cursor",g._v$=Q),C!==g._v$2&&B.classList.toggle("ap-blink",g._v$2=C),g._v$3=_(B,E,g._v$3),g}),{_v$:void 0,_v$2:void 0,_v$3:void 0}),B})()};const Dg=X(''),wg=X(''),hg=X(''),lg=X(''),yg=X('
'),Gg=X('');function Mg(A){let g=Math.floor(A);const I=Math.floor(g/86400);g%=86400;const B=Math.floor(g/3600);g%=3600;const Q=Math.floor(g/60);return g%=60,I>0?`${kg(I)}:${kg(B)}:${kg(Q)}:${kg(g)}`:B>0?`${kg(B)}:${kg(Q)}:${kg(g)}`:`${kg(Q)}:${kg(g)}`}function kg(A){return A<10?`0${A}`:A.toString()}var Ng=A=>{const g=A=>g=>{g.preventDefault(),A(g)},I=()=>"number"==typeof A.currentTime?Mg(A.currentTime):"--:--",B=()=>"number"==typeof A.remainingTime?"-"+Mg(A.remainingTime):I(),Q=h((()=>"number"==typeof A.duration?A.markers.filter((g=>g[0]{const g=A.currentTarget.offsetWidth,I=A.currentTarget.getBoundingClientRect(),B=A.clientX-I.left;return 100*Math.max(0,B/g)+"%"},[E,e]=D(!1),i=function(A,g){let I=!0;return function(){if(I){I=!1;for(var B=arguments.length,Q=new Array(B),C=0;CI=!0),g)}}}(A.onSeekClick,50),t=g=>{g.altKey||g.shiftKey||g.metaKey||g.ctrlKey||0!==g.button||(e(!0),A.onSeekClick(C(g)))},o=A=>{A.altKey||A.shiftKey||A.metaKey||A.ctrlKey||E()&&i(C(A))},s=()=>{e(!1)},n=g((A=>{A.stopPropagation()}));return document.addEventListener("mouseup",s),M((()=>{document.removeEventListener("mouseup",s)})),(()=>{const C=yg.cloneNode(!0),E=C.firstChild,e=E.firstChild,i=e.nextSibling,s=E.nextSibling,r=A.ref;return"function"==typeof r?$(r,C):A.ref=C,AA(C,b(j,{get when(){return A.isPausable},get children(){const I=hg.cloneNode(!0);return P(I,"click",g(A.onPlayClick),!0),AA(I,b(T,{get children(){return[b(Z,{get when(){return A.isPlaying},get children(){return Dg.cloneNode(!0)}}),b(Z,{get when(){return!A.isPlaying},get children(){return wg.cloneNode(!0)}})]}})),I}}),E),AA(e,I),AA(i,B),AA(C,b(j,{get when(){return"number"==typeof A.progress||A.isSeekable},get children(){const I=lg.cloneNode(!0),B=I.firstChild,C=B.firstChild.firstChild;return B.$$mousemove=o,B.$$mousedown=t,AA(B,b(v,{get each(){return Q()},children:(I,B)=>(()=>{const Q=Gg.cloneNode(!0),C=Q.firstChild,E=C.nextSibling;var e;return P(Q,"mousedown",n,!0),P(Q,"click",(e=B(),g((()=>{A.onSeekClick({marker:e})}))),!0),AA(E,(()=>(A=>""===A[1]?Mg(A[0]):`${Mg(A[0])} - ${A[1]}`)(I))),w((g=>{const B=(g=>g[0]/A.duration*100+"%")(I),E=!!(g=>"number"==typeof A.currentTime&&g[0]<=A.currentTime)(I);return B!==g._v$&&Q.style.setProperty("left",g._v$=B),E!==g._v$2&&C.classList.toggle("ap-marker-past",g._v$2=E),g}),{_v$:void 0,_v$2:void 0}),Q})()}),null),w((g=>_(C,{width:"100%",transform:`scaleX(${A.progress||0}`,"transform-origin":"left center"},g))),I}}),s),P(s,"click",g(A.onFullscreenClick),!0),w((()=>C.classList.toggle("ap-seekable",!!A.isSeekable))),C})()};z(["click","mousedown","mousemove"]);const ug=X('
💥
');var Fg=A=>ug.cloneNode(!0);const dg=X('
');var fg=A=>dg.cloneNode(!0);const Yg=X('
Stream offline
');var Rg=A=>(()=>{const g=Yg.cloneNode(!0),I=g.firstChild;return w((g=>_(I,{"font-family":A.fontFamily},g))),g})();const Jg=X('
');var pg=A=>(()=>{const g=Jg.cloneNode(!0);var I;return P(g,"click",(I=A.onClick,A=>{A.preventDefault(),I(A)}),!0),g})();z(["click"]);const Sg=X('
');var Lg=A=>{const g=A.logger,I=A.core,B=A.autoPlay,[Q,C]=Cg({coreState:"stopped",lines:[],cursor:void 0,charW:A.charW,charH:A.charH,bordersW:A.bordersW,bordersH:A.bordersH,containerW:0,containerH:0,showStartOverlay:!B,isPausable:!0,isSeekable:!0,isFullscreen:!1,currentTime:null,remainingTime:null,progress:null,blink:!0,cursorHold:!1}),[E,e]=D({cols:A.cols,rows:A.rows}),[i,t]=D(void 0),[o,s]=Cg([]),[n,r]=D(!1),a=()=>E().cols||80,c=()=>E().rows||24,y=()=>!1===A.controls?0:32;let k,N,u,F,d,f,Y,R,J;function p(){gA(),X(),z()}function S(A){A.rows{let{cols:g,rows:I,duration:B,poster:Q,markers:C}=A;S({cols:g,rows:I}),t(B),s(C),L(Q)})),I.addEventListener("play",(()=>{C("showStartOverlay",!1)})),I.addEventListener("playing",(()=>{C("coreState","playing"),H(),P(),O()})),I.addEventListener("stopped",(()=>{C("coreState","stopped"),p()})),I.addEventListener("loading",(()=>{C("coreState","loading"),p()})),I.addEventListener("offline",(()=>{C("coreState","offline"),p()})),I.addEventListener("errored",(()=>{C({coreState:"errored",showStartOverlay:!1})})),I.addEventListener("resize",S),I.addEventListener("reset",(A=>{S(A),H()})),I.addEventListener("seeked",(()=>{z()})),I.addEventListener("terminalUpdate",(()=>{void 0===k&&(k=requestAnimationFrame(H))}));const U=()=>{J=new ResizeObserver(function(A,g){let I;return function(){for(var B=arguments.length,Q=new Array(B),C=0;CA.apply(this,Q)),g)}}((A=>{C({containerW:d.offsetWidth,containerH:d.offsetHeight}),d.dispatchEvent(new CustomEvent("resize",{detail:{el:f}}))}),10)),J.observe(d)};G((async()=>{g.info("player mounted"),g.debug("font measurements",{charW:Q.charW,charH:Q.charH}),U();const{isPausable:A,isSeekable:E,poster:e}=await I.init();C({isPausable:A,isSeekable:E,containerW:d.offsetWidth,containerH:d.offsetHeight}),L(e),B&&I.play()})),M((()=>{I.stop(),gA(),X(),J.disconnect()}));const H=()=>{const A=I.getChangedLines();A&&l((()=>{A.forEach(((A,g)=>{C("lines",g,ig(A))}))})),C("cursor",ig(I.getCursor())),C("cursorHold",!0),k=void 0},K=h((()=>{g.debug(`containerW = ${Q.containerW}`);const I=Q.charW*a()+Q.bordersW,B=Q.charH*c()+Q.bordersH;let C=A.fit??"width";if("both"===C||Q.isFullscreen){C=Q.containerW/(Q.containerH-y())>I/B?"height":"width"}if(!1===C||"none"===C)return{};if("width"===C){const A=Q.containerW/I;return{scale:A,width:Q.containerW,height:B*A+y()}}if("height"===C){const A=(Q.containerH-y())/B;return{scale:A,width:I*A,height:Q.containerH}}throw`unsupported fit mode: ${C}`})),m=()=>{C("isFullscreen",document.fullscreenElement??document.webkitFullscreenElement)},q=()=>{Q.isFullscreen?(document.exitFullscreen??document.webkitExitFullscreen??(()=>{})).apply(document):(d.requestFullscreen??d.webkitRequestFullscreen??(()=>{})).apply(d)},v=A=>{if(!(A.altKey||A.metaKey||A.ctrlKey))if(A.shiftKey){if("ArrowLeft"==A.key)I.seek("<<<");else{if("ArrowRight"!=A.key)return;I.seek(">>>")}A.preventDefault()}else{if(" "==A.key)I.togglePlay();else if("."==A.key)I.step(),z();else if("f"==A.key)q();else if("ArrowLeft"==A.key)I.seek("<<");else if("ArrowRight"==A.key)I.seek(">>");else if("["==A.key)I.seek({marker:"prev"});else if("]"==A.key)I.seek({marker:"next"});else{if(!(A.key.charCodeAt(0)>=48&&A.key.charCodeAt(0)<=57))return;{const g=(A.key.charCodeAt(0)-48)/10;I.seek(100*g+"%")}}A.preventDefault()}},x=()=>{Q.isFullscreen&&IA(!0)},W=()=>{Q.isFullscreen||IA(!1)},O=()=>{u=setInterval(z,100)},X=()=>{clearInterval(u)},z=()=>{const A=I.getCurrentTime(),g=I.getRemainingTime(),B=I.getProgress();C({currentTime:A,remainingTime:g,progress:B})},P=()=>{F=setInterval((()=>{C((A=>{const g={blink:!A.blink};return g.blink&&(g.cursorHold=!1),g}))}),500)},gA=()=>{clearInterval(F),C("blink",!0)},IA=A=>{clearTimeout(N),A&&(N=setTimeout((()=>IA(!1)),2e3)),r(A)},BA=(()=>{const g=Sg.cloneNode(!0),B=g.firstChild;"function"==typeof d?$(d,g):d=g,g.addEventListener("webkitfullscreenchange",m),g.addEventListener("fullscreenchange",m),g.$$mousemove=x,g.$$keydown=v,g.addEventListener("keypress",v);return"function"==typeof f?$(f,B):f=B,B.$$mousemove=()=>IA(!0),B.addEventListener("mouseleave",W),AA(B,b(cg,{get cols(){return a()},get rows(){return c()},get scale(){return K()?.scale},get blink(){return Q.blink},get lines(){return Q.lines},get cursor(){return Q.cursor},get cursorHold(){return Q.cursorHold},get fontFamily(){return A.terminalFontFamily},get lineHeight(){return A.terminalLineHeight},ref(A){"function"==typeof Y?Y(A):Y=A}}),null),AA(B,b(j,{get when(){return!1!==A.controls},get children(){return b(Ng,{get duration(){return i()},get currentTime(){return Q.currentTime},get remainingTime(){return Q.remainingTime},get progress(){return Q.progress},markers:o,get isPlaying(){return"playing"==Q.coreState},get isPausable(){return Q.isPausable},get isSeekable(){return Q.isSeekable},onPlayClick:()=>I.togglePlay(),onFullscreenClick:q,onSeekClick:A=>I.seek(A),ref(A){"function"==typeof R?R(A):R=A}})}}),null),AA(B,b(T,{get children(){return[b(Z,{get when(){return Q.showStartOverlay},get children(){return b(pg,{onClick:()=>I.play()})}}),b(Z,{get when(){return"loading"==Q.coreState},get children(){return b(fg,{})}}),b(Z,{get when(){return"offline"==Q.coreState},get children(){return b(Rg,{get fontFamily(){return A.terminalFontFamily}})}}),b(Z,{get when(){return"errored"==Q.coreState},get children(){return b(Fg,{})}})]}}),null),w((I=>{const Q=!!(!0===A.controls||"auto"===A.controls&&n()),C=`ap-player asciinema-theme-${A.theme??"asciinema"}`,E=(()=>{const g={};!1!==A.fit&&"none"!==A.fit||void 0===A.terminalFontSize||("small"===A.terminalFontSize?g["font-size"]="12px":"medium"===A.terminalFontSize?g["font-size"]="18px":"big"===A.terminalFontSize?g["font-size"]="24px":g["font-size"]=A.terminalFontSize);const I=K();return void 0!==I.width&&(g.width=`${I.width}px`,g.height=`${I.height}px`),g})();return Q!==I._v$&&g.classList.toggle("ap-hud",I._v$=Q),C!==I._v$2&&V(B,I._v$2=C),I._v$3=_(B,E,I._v$3),I}),{_v$:void 0,_v$2:void 0,_v$3:void 0}),g})();return BA};z(["keydown","mousemove"]);class Ug{log(){}debug(){}info(){}warn(){}error(){}}class Hg{constructor(A,g){this.logger=A,this.prefix=g}log(A){for(var g=arguments.length,I=new Array(g>1?g-1:0),B=1;B1?g-1:0),B=1;B1?g-1:0),B=1;B1?g-1:0),B=1;B1?g-1:0),B=1;BI=>{g(A(I))}}(A))}flatMap(A){return this.transform(function(A){return g=>I=>{A(I).forEach(g)}}(A))}filter(A){return this.transform(function(A){return g=>I=>{A(I)&&g(I)}}(A))}take(A){return this.transform(function(A){let g=0;return I=>B=>{gB=>{g+=1,g>A&&I(B)}}(A))}transform(A){return new Kg(this.input,this.xfs.concat([A]))}multiplex(A,g){return new Kg(new qg(this[Symbol.iterator](),A[Symbol.iterator](),g))}toArray(){return Array.from(this)}[Symbol.iterator](){let A=0,g=[],I=!1;const B=(Q=this.xfs,C=A=>g.push(A),Q.reverse().reduce(((A,g)=>{const I=mg(g(A.step));return{step:I.step,flush:()=>{I.flush(),A.flush()}}}),mg(C)));var Q,C;return{next:()=>{for(A===g.length&&(g=[],A=0);0===g.length;){const A=this.input.next();if(A.done)break;B.step(A.value)}return 0!==g.length||I||(B.flush(),I=!0),g.length>0?{done:!1,value:g[A++]}:{done:!0}}}}}function mg(A){return"function"==typeof A?{step:A,flush:()=>{}}:A}class qg{constructor(A,g,I){this.left=A,this.right=g,this.comparator=I}[Symbol.iterator](){let A,g;return{next:()=>{if(void 0===A&&void 0!==this.left){const g=this.left.next();g.done?this.left=void 0:A=g.value}if(void 0===g&&void 0!==this.right){const A=this.right.next();A.done?this.right=void 0:g=A.value}if(void 0===A&&void 0===g)return{done:!0};if(void 0===A){const A=g;return g=void 0,{done:!1,value:A}}if(void 0===g){const g=A;return A=void 0,{done:!1,value:g}}if(this.comparator(A,g)){const g=A;return A=void 0,{done:!1,value:g}}{const A=g;return g=void 0,{done:!1,value:A}}}}}}async function bg(A){let g,I;if(A instanceof Response){const B=await A.text(),Q=function(A){const g=A.split("\n");let I;try{I=JSON.parse(g[0])}catch(A){return}const B=new Kg(g).drop(1).filter((A=>"["===A[0])).map(JSON.parse).toArray();return{header:I,events:B}}(B);void 0!==Q?(g=Q.header,I=Q.events):g=JSON.parse(B)}else if("object"==typeof A&&"number"==typeof A.version)g=A;else{if(!Array.isArray(A))throw"invalid data";g=A[0],I=A.slice(1,A.length)}if(1===g.version)return function(A){let g=0;const I=new Kg(A.stdout).map((A=>(g+=A[0],[g,"o",A[1]])));return{cols:A.width,rows:A.height,events:I}}(g);if(2===g.version)return function(A,g){return{cols:A.width,rows:A.height,events:g,idleTimeLimit:A.idle_time_limit}}(g,I);throw`asciicast v${g.version} format not supported`}function vg(A){if("r"===A[1]){const[g,I]=A[2].split("x");return[A[0],"o",`[8;${I};${g};t`]}return A}function xg(A){return"number"==typeof A?[A,"m",""]:[A[0],"m",A[1]]}function jg(){let A=0;return function(g){return"m"===g[1]?[g[0],g[1],{index:A++,time:g[0],label:g[2]}]:g}}class Tg{constructor(){this.items=[],this.onPush=void 0}push(A){this.items.push(A),void 0!==this.onPush&&(this.onPush(this.popAll()),this.onPush=void 0)}popAll(){if(this.items.length>0){const A=this.items;return this.items=[],A}{const A=this;return new Promise((g=>{A.onPush=g}))}}}function Zg(A,g,I,B,Q){return I>0?function(A,g,I,B){let Q=arguments.length>4&&void 0!==arguments[4]?arguments[4]:1/60;const C=new Tg,E=Wg();let e=!1,i=-Q;return setTimeout((async()=>{for(;!e;){const t=await C.popAll();if(e)return;for(const C of t){const t=C[0]-B+I;if(t-i0&&(await Og(o),e))return;g(C[0]),A(C[2]),i=t}}}),0),{pushEvent(A){if("o"===A[1])C.push(A);else if("r"===A[1]){const[g,I]=A[2].split("x");C.push([A[0],"o",`[8;${I};${g};t`])}},pushText(A){const g=(Wg()-E)/1e3;C.push([g,"o",A])},stop(){e=!0,C.push(void 0)}}}(A,g,I,B??0,Q):function(A){return{pushEvent(g){"o"===g[1]&&A(g[2])},pushText(g){A(g)},stop(){}}}(A)}function Wg(){return(new Date).getTime()}function Og(A){return new Promise((g=>{setTimeout(g,1e3*A)}))}function Xg(A){return Math.min(500*Math.pow(2,A),5e3)}function zg(A){if(A.length<13)return;const g=function(A){const g=Vg(A.subarray(0,4)),I=Vg(A.subarray(4,8));return g+I/1e6}(A.subarray(0,8)),I=Vg(A.subarray(8,12));return{time:g,data:A.subarray(12,12+I),len:I+12}}function Vg(A){return A[0]+256*A[1]+256*A[2]*256+256*A[3]*256*256}const Pg=new Map([["benchmark",function(A,g){let I,{url:B,iterations:Q=10}=A,{feed:C,now:E}=g,e=0;return{async init(){const A=await bg(await fetch(B)),{cols:g,rows:Q,events:C}=A;I=Array.from(C).filter((A=>{let[g,I,B]=A;return"o"===I})).map((A=>{let[g,I,B]=A;return[g,B]}));const E=I[I.length-1][0];for(const[A,g]of I)e+=new Blob([g]).size;return{cols:g,rows:Q,duration:E}},play(){const A=E();for(let A=0;A{const A=new Date,g=A.getHours(),I=A.getMinutes(),E=[];E.push("\r");for(let A=0;A{r().forEach(E)};return{init:()=>{const A=[s].concat(r());return{cols:e,rows:i,duration:1440,poster:A}},play:()=>(E(s),a(),n=setInterval(a,1e3),!0),stop:()=>{clearInterval(n)},getCurrentTime:()=>{const A=new Date;return 60*A.getHours()+A.getMinutes()}}}],["eventsource",function(A,g){let I,B,{url:Q,bufferTime:C=.1,minFrameTime:E}=A,{feed:e,reset:i,setState:t,logger:o}=g;o=new Hg(o,"eventsource: ");let s=new UA;function n(A){void 0!==B&&B.stop(),B=Zg(e,(A=>s.setTime(A)),C,A,E)}return{play:()=>{I=new EventSource(Q),I.addEventListener("open",(()=>{o.info("opened"),n()})),I.addEventListener("error",(A=>{o.info("errored"),o.debug({e:A}),t("loading")})),I.addEventListener("message",(A=>{const g=JSON.parse(A.data);if(Array.isArray(g))B.pushEvent(g);else if(void 0!==g.cols||void 0!==g.width){const A=g.cols??g.width,I=g.rows??g.height;o.debug(`vt reset (${A}x${I})`),t("playing"),n(g.time),i(A,I,g.init??void 0),s=new LA,"number"==typeof g.time&&s.setTime(g.time)}else"offline"===g.state&&(o.info("stream offline"),t("offline"),s=new UA)})),I.addEventListener("done",(()=>{o.info("closed"),I.close(),t("stopped",{reason:"ended"})}))},stop:()=>{void 0!==B&&B.stop(),void 0!==I&&I.close()},getCurrentTime:()=>s.getTime()}}],["random",function(A,g){let{feed:I,setTimeout:B}=g;const Q=" ".charCodeAt(0),C="~".charCodeAt(0)-Q;let E;const e=()=>{const A=Math.pow(5,4*Math.random());E=B(i,A)},i=()=>{e();const A=String.fromCharCode(Q+Math.floor(Math.random()*C));I(A)};return()=>(e(),()=>clearInterval(E))}],["recording",function(A,g,I){let B,Q,C,E,e,i,t,o,s,{feed:n,onInput:r,onMarker:a,now:c,setTimeout:D,setState:w,logger:h}=g,{idleTimeLimit:l,startAt:y,loop:G,posterTime:M,markers:k,pauseOnMarkers:N,cols:u,rows:F}=I,d=0,f=0,Y=0;async function R(A,g){const I=await fetch(A,g);if(!I.ok)throw`failed fetching recording from ${A}: ${I.status} ${I.statusText}`;return I}function J(){const A=C[d];A?t=D(p,function(A){let g=1e3*A-(c()-o);return g<0&&(g=0),g}(A[0])):(S(),Y++,!0===G||"number"==typeof G&&Y1e3*g[0]);J()}function S(){clearTimeout(t),t=null}function L(A){const[g,I,B]=A;if("o"===I)n(B);else if("i"===I)r(B);else if("m"===I&&(a(B),N))return U(),s=1e3*g,w("stopped",{reason:"paused"}),!0;return!1}function U(){return!t||(S(),s=c()-o,!0)}function H(){o=c()-s,s=null,J()}function K(A){const g=!!t;U();const I=(s??0)/1e3;if("string"==typeof A)"<<"===A?A=I-5:">>"===A?A=I+5:"<<<"===A?A=I-.1*e:">>>"===A?A=I+.1*e:"%"===A[A.length-1]&&(A=parseFloat(A.substring(0,A.length-1))/100*e);else if("object"==typeof A)if("prev"===A.marker)A=m(I)??0,g&&I-A<1&&(A=m(A)??0);else if("next"===A.marker)A=function(A){if(0==E.length)return;let g,I=E.length-1,B=E[I];for(;B&&B[0]>A;)g=B[0],B=E[--I];return g}(I)??e;else if("number"==typeof A.marker){const g=E[A.marker];if(void 0===g)throw`invalid marker index: ${A.marker}`;A=g[0]}const B=Math.min(Math.max(A,0),e);B[A[0],"o",A[1]])),C=new Kg(I).map((A=>[A[0],"i",A[1]])),E=new Kg(B).map(xg);return Q.multiplex(C,((A,g)=>A[0]A[0]1&&void 0!==arguments[1]?arguments[1]:1/60;return B=>{let Q=0,C=0;return{step:A=>{Q++,void 0!==g?A[1]===g[1]&&A[0]-g[0]{void 0!==g&&(B(g),C++),A.debug(`batched ${Q} frames to ${C} frames`)}}}}(g,C)).map(function(A,g,I){let B=0,Q=0;return function(C){const E=C[0]-B-A;return B=C[0],E>0&&(Q+=E,C[0]"m"!==A[1])).multiplex(e,((A,g)=>A[0]"i"===A[1]?[A[0]+E,A[1],A[2]]:A)),i.sort(((A,g)=>A[0]-g[0])));const o=i[i.length-1][0],s=B-t.offset;return{...A,events:i,duration:o,effectiveStartAt:s}}(await g(await function(A){let{url:g,data:I,fetchOpts:B={}}=A;if("string"==typeof g)return R(g,B);if(Array.isArray(g))return Promise.all(g.map((A=>R(A,B))));if(void 0!==I)return"function"==typeof I&&(I=I()),I instanceof Promise||(I=Promise.resolve(I)),I.then((A=>"string"==typeof A||A instanceof ArrayBuffer?new Response(A):A));throw"failed fetching recording file: url/data missing in src"}(A),{encoding:s}),h,{idleTimeLimit:l,startAt:y,minFrameTime:I,inputOffset:t,markers_:k});if(({cols:B,rows:Q,events:C,duration:e,effectiveStartAt:i}=n),u=u??B,F=F??Q,0===C.length)throw"recording is missing events";void 0!==o&&function(A,g){const I=document.createElement("a"),B=A.events.map((A=>"m"===A[1]?[A[0],A[1],A[2].label]:A)),Q=function(A){return`${JSON.stringify({version:2,width:A.cols,height:A.rows})}\n${A.events.map(JSON.stringify).join("\n")}\n`}({...A,events:B});I.href=URL.createObjectURL(new Blob([Q],{type:"text/plain"})),I.download=g,I.click()}(n,o);const r=void 0!==M?(a=M,C.filter((A=>A[0]A[2]))):void 0;var a;return E=C.filter((A=>"m"===A[1])).map((A=>[A[0],A[2].label])),{cols:B,rows:Q,duration:e,poster:r,markers:E}},play:function(){return t||(void 0===C[d]&&(i=0),null!==i&&K(i),H()),!0},pause:U,seek:K,step:function(){let A=C[d++];for(;void 0!==A&&"o"!==A[1];)A=C[d++];if(void 0===A)return;n(A[2]);const g=A[0];f=g,s=1e3*g,i=null},stop:U,getCurrentTime:function(){return t?(c()-o)/1e3:(s??0)/1e3}}}],["websocket",function(A,g){let{url:I,bufferTime:B=.1,reconnectDelay:Q=Xg,minFrameTime:C}=A,{feed:E,reset:e,setState:i,logger:t}=g;t=new Hg(t,"websocket: ");const o=new TextDecoder;let s,n,r,a=new UA,c=0,D=!1;function w(A){void 0!==n&&n.stop(),n=Zg(E,(A=>a.setTime(A)),B,A,C)}function h(A){if("string"==typeof A.data)t.info("activating asciicast-compatible handler"),s.onmessage=l,l(A);else{const g=new Uint8Array(A.data);if(65==g[0]&&76==g[1]&&105==g[2]&&83==g[3])if(1==g[4]){t.info("activating ALiS v1 handler");const A=g[5];0==A?t.debug("text compression: none"):(t.error(`unsupported compression algorithm (${A})`),s.close()),s.onmessage=y}else t.warn(`unsupported ALiS version (${g[4]})`),s.close();else{t.info("activating raw text handler");const I=o.decode(g),B=function(A){const g=A.match(/\x1b\[8;(\d+);(\d+)t/);if(null!==g)return[parseInt(g[2],10),parseInt(g[1],10)]}(I)??function(A){const g=A.match(/\[.*COLUMNS="(\d{1,3})" LINES="(\d{1,3})".*\]/);if(null!==g)return[parseInt(g[1],10),parseInt(g[2],10)]}(I);if(void 0!==B){const[A,g]=B;M(A,g,0,void 0)}s.onmessage=G,G(A)}}}function l(A){const g=JSON.parse(A.data);Array.isArray(g)?n.pushEvent(g):void 0!==g.cols||void 0!==g.width?M(g.cols??g.width,g.rows??g.height,g.time,g.init??void 0):"offline"===g.status&&k()}function y(A){const g=A.data,I=new DataView(g),B=I.getUint8(0);if(1===B){const A=I.getUint16(1,!0),B=I.getUint16(3,!0),Q=I.getFloat32(5,!0),C=I.getUint32(9,!0);M(A,B,Q,C>0?o.decode(new Uint8Array(g,13,C)):void 0)}else if(111===B){const A=I.getFloat32(1,!0),B=I.getUint32(5,!0),Q=o.decode(new Uint8Array(g,9,B));n.pushEvent([A,"o",Q])}else if(114===B){const A=I.getFloat32(1,!0),g=I.getUint16(5,!0),B=I.getUint16(7,!0);n.pushEvent([A,"r",`${g}x${B}`])}else 4===B?k():t.debug(`unknown frame type: ${B}`)}function G(A){n.pushText(o.decode(A.data))}function M(A,g,I,B){t.debug(`stream reset (${A}x${g} @${I})`),i("playing"),w(I),e(A,g,B),a=new LA,"number"==typeof I&&a.setTime(I)}function k(){t.info("stream offline"),i("offline"),a=new UA}function N(){s=new WebSocket(I),s.binaryType="arraybuffer",s.onopen=()=>{t.info("opened"),w(),r=setTimeout((()=>{c=0}),1e3)},s.onmessage=h,s.onclose=A=>{if(D||1e3===A.code||1005===A.code)t.info("closed"),i("stopped",{reason:"ended"});else{clearTimeout(r);const A=Q(c++);t.info(`unclean close, reconnecting in ${A}...`),i("loading"),setTimeout(N,A)}}}return{play:()=>{N()},stop:()=>{D=!0,void 0!==n&&n.stop(),void 0!==s&&s.close()},getCurrentTime:()=>a.getTime()}}]]),_g=new Map([["asciicast",bg],["typescript",async function(A,g){let{encoding:I}=g;const B=new TextDecoder(I);let Q,C,E=(await A[0].text()).split("\n").filter((A=>A.length>0)).map((A=>A.split(" ")));E[0].length<3&&(E=E.map((A=>["O",A[0],A[1]])));const e=await A[1].arrayBuffer(),i=new Uint8Array(e),t=i.findIndex((A=>10==A))+1,o=B.decode(i.subarray(0,t)).match(/COLUMNS="(\d+)" LINES="(\d+)"/);null!==o&&(Q=parseInt(o[1],10),C=parseInt(o[2],10));const s={array:i,cursor:t};let n=s;if(void 0!==A[2]){const g=await A[2].arrayBuffer();n={array:new Uint8Array(g),cursor:t}}const r=[];let a=0;for(const A of E)if(a+=parseFloat(A[1]),"O"===A[0]){const g=parseInt(A[2],10),I=s.array.subarray(s.cursor,s.cursor+g),Q=B.decode(I);r.push([a,"o",Q]),s.cursor+=g}else if("I"===A[0]){const g=parseInt(A[2],10),I=n.array.subarray(n.cursor,n.cursor+g),Q=B.decode(I);r.push([a,"i",Q]),n.cursor+=g}else if("S"===A[0]&&"SIGWINCH"===A[2]){const g=parseInt(A[4].slice(5),10),I=parseInt(A[3].slice(5),10);r.push([a,"r",`${g}x${I}`])}else"H"===A[0]&&"COLUMNS"===A[2]?Q=parseInt(A[3],10):"H"===A[0]&&"LINES"===A[2]&&(C=parseInt(A[3],10));return Q=Q??80,C=C??24,{cols:Q,rows:C,events:r}}],["ttyrec",async function(A,g){let{encoding:I}=g;const B=new TextDecoder(I),Q=await A.arrayBuffer(),C=new Uint8Array(Q),E=zg(C),e=E.time,i=B.decode(E.data).match(/\x1b\[8;(\d+);(\d+)t/),t=[];let o=80,s=24;null!==i&&(o=parseInt(i[2],10),s=parseInt(i[1],10));let n=0,r=zg(C);for(;void 0!==r;){const A=r.time-e,g=B.decode(r.data);t.push([A,"o",g]),n+=r.len,r=zg(C.subarray(n))}return{cols:o,rows:s,events:t}}]]);return A.create=function(A,g){let I=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{};const B=I.logger??new Ug,Q=new TA(function(A){if("function"==typeof A)return A;"string"==typeof A&&(A="ws://"==A.substring(0,5)||"wss://"==A.substring(0,6)?{driver:"websocket",url:A}:"clock:"==A.substring(0,6)?{driver:"clock"}:"random:"==A.substring(0,7)?{driver:"random"}:"benchmark:"==A.substring(0,10)?{driver:"benchmark",url:A.substring(10)}:{driver:"recording",url:A});void 0===A.driver&&(A.driver="recording");if("recording"==A.driver&&(void 0===A.parser&&(A.parser="asciicast"),"string"==typeof A.parser)){if(!_g.has(A.parser))throw`unknown parser: ${A.parser}`;A.parser=_g.get(A.parser)}if(Pg.has(A.driver)){const g=Pg.get(A.driver);return(I,B)=>g(A,I,B)}throw`unsupported driver: ${JSON.stringify(A)}`}(A),{logger:B,cols:I.cols,rows:I.rows,loop:I.loop,speed:I.speed,preload:I.preload,startAt:I.startAt,poster:I.poster,markers:I.markers,pauseOnMarkers:I.pauseOnMarkers,idleTimeLimit:I.idleTimeLimit}),C=function(A,g){const I=80,B=24,Q=document.createElement("div");let C;Q.style.height="0px",Q.style.overflow="hidden",Q.style.fontSize="15px",document.body.appendChild(Q);const E=O((()=>(C=b(cg,{cols:I,rows:B,lineHeight:g,fontFamily:A,lines:[]}),C)),Q),e={charW:C.clientWidth/I,charH:C.clientHeight/B,bordersW:C.offsetWidth-C.clientWidth,bordersH:C.offsetHeight-C.clientHeight};return E(),document.body.removeChild(Q),e}(I.terminalFontFamily,I.terminalLineHeight),E={logger:B,core:Q,cols:I.cols,rows:I.rows,fit:I.fit,controls:I.controls??"auto",autoPlay:I.autoPlay??I.autoplay,terminalFontSize:I.terminalFontSize,terminalFontFamily:I.terminalFontFamily,terminalLineHeight:I.terminalLineHeight,theme:I.theme,...C};let e;const i=O((()=>(e=b(Lg,E),e)),g),t={el:e,dispose:i,getCurrentTime:()=>Q.getCurrentTime(),getDuration:()=>Q.getDuration(),play:()=>Q.play(),pause:()=>Q.pause(),seek:A=>Q.seek(A),addEventListener:(A,g)=>Q.addEventListener(A,g.bind(t))};return t},A}({}); diff --git a/homepage/home_static/demo.cast b/homepage/home_static/demo.cast deleted file mode 100644 index 03adfbfeb..000000000 --- a/homepage/home_static/demo.cast +++ /dev/null @@ -1,242 +0,0 @@ -{"version": 2, "width": 133, "height": 24, "timestamp": 1648331634, "env": {"SHELL": "/bin/zsh", "TERM": "xterm-256color"}} -[0.058188, "o", "\u001b[1m\u001b[7m%\u001b[27m\u001b[1m\u001b[0m \r \r"] -[0.059315, "o", "\u001b]7;file:///home/wilfred/projects/difftastic\u001b\\"] -[0.059474, "o", "\r\u001b[0m\u001b[27m\u001b[24m\u001b[J$ \u001b[K\u001b[?2004h"] -[2.5995, "o", "# Difftastic is a tool for comparing files based on syntax."] -[3.226385, "o", "\u001b[?2004l\r\r\n"] -[3.226734, "o", "\u001b[1m\u001b[7m%\u001b[27m\u001b[1m\u001b[0m \r \r"] -[3.227569, "o", "\u001b]7;file:///home/wilfred/projects/difftastic\u001b\\"] -[3.227785, "o", "\r\u001b[0m\u001b[27m\u001b[24m\u001b[J$ \u001b[K\u001b[?2004h"] -[6.365599, "o", "# You can give it two paths to compare, just like diff."] -[7.648592, "o", "\u001b[?2004l\r\r\n"] -[7.648843, "o", "\u001b[1m\u001b[7m%\u001b[27m\u001b[1m\u001b[0m \r \r"] -[7.649941, "o", "\u001b]7;file:///home/wilfred/projects/difftastic\u001b\\"] -[7.650048, "o", "\r\u001b[0m\u001b[27m\u001b[24m\u001b[J$ \u001b[K\u001b[?2004h"] -[10.137345, "o", "d"] -[10.257334, "o", "\bdi"] -[10.334579, "o", "f"] -[10.483799, "o", "f"] -[10.67091, "o", "t"] -[10.736178, "o", " "] -[10.924637, "o", "s"] -[10.987535, "o", "a"] -[11.092373, "o", "m"] -[11.283115, "o", "ple_files\u001b[1m/\u001b[0m"] -[11.689602, "o", "\b\u001b[0m/c"] -[11.794798, "o", "l"] -[11.950613, "o", "o"] -[12.096605, "o", "jure_"] -[12.435091, "o", "b"] -[12.515293, "o", "efore.clj\u001b[1m \u001b[0m"] -[13.113687, "o", "\b\u001b[0m s"] -[13.199507, "o", "a"] -[13.351514, "o", "m"] -[13.494273, "o", "ple_files\u001b[1m/\u001b[0m"] -[13.867224, "o", "\b\u001b[0m/c"] -[13.956386, "o", "l"] -[14.158282, "o", "o"] -[14.260931, "o", "jure_"] -[14.575625, "o", "a"] -[14.794025, "o", "fter.clj\u001b[1m \u001b[0m"] -[15.340386, "o", "\b\u001b[0m \b\u001b[?2004l\r\r\n"] -[15.344656, "o", "\u001b[1m\u001b[93msample_files/clojure_after.clj\u001b[39m\u001b[0m --- 1/1 --- Clojure\r\n1 \u001b[94;3m;; Example from Autochrome, under EPL-1.0 license.\u001b[0m 1 \u001b[94;3m;; Example from Autochrome, under EPL-1.0 license.\u001b[0m \r\n2 (defn example 2 (defn example \r\n3 [x] 3 [x] \r\n\u001b[91m4 \u001b[39m \u001b[91;1m(\u001b[0m\u001b[91mprintln\u001b[0m \u001b[91m\"hello!\"\u001b[0m\u001b[91;1m)\u001b[0m \u001b[2m. \u001b[0m\r\n5 {\u001b[1m:more\u001b[0m (inc x) \u001b[92m4 \u001b[39m \u001b[92;1m(\u001b[0m\u001b[92m->\u001b[0m {\u001b[1m:more\u001b[0m (inc x) \r\n6 \u001b[1m:less\u001b[0m (dec x)}) 5 \u001b[1m:less\u001b[0m (dec x)} \r\n\u001b[2m \u001b[0m "] -[15.34478, "o", " \u001b[92m6 \u001b[39m \u001b[92;1m(\u001b[0m\u001b[92massoc\u001b[0m \u001b[92;1m:twice\u001b[0m \u001b[92;1m(\u001b[0m\u001b[92m+\u001b[0m \u001b[92mx\u001b[0m \u001b[92mx\u001b[0m\u001b[92;1m)\u001b[0m\u001b[92;1m)\u001b[0m\u001b[92;1m)\u001b[0m) \r\n\r\n"] -[15.345119, "o", "\u001b[1m\u001b[7m%\u001b[27m\u001b[1m\u001b[0m \r \r"] -[15.346128, "o", "\u001b]7;file:///home/wilfred/projects/difftastic\u001b\\"] -[15.346218, "o", "\r\u001b[0m\u001b[27m\u001b[24m\u001b[J$ \u001b[K\u001b[?2004h"] -[20.072257, "o", "# Difftastic has support for git too! Let's look at some recent commits."] -[20.908263, "o", "\u001b[?2004l\r\r\n"] -[20.908512, "o", "\u001b[1m\u001b[7m%\u001b[27m\u001b[1m\u001b[0m \r \r"] -[20.909869, "o", "\u001b]7;file:///home/wilfred/projects/difftastic\u001b\\"] -[20.910001, "o", "\r\u001b[0m\u001b[27m\u001b[24m\u001b[J$ \u001b[K\u001b[?2004h"] -[25.174718, "o", "GIT_EXTERNAL_DIFF=difft git log -p --ext-diff"] -[27.066311, "o", "\u001b[?2004l\r\r\n"] -[27.073778, "o", "\u001b[?1h\u001b=\r"] -[27.073956, "o", "\u001b[33mcommit 905fc9ec8be333bee05595091207d30d69ec14b9\u001b[m\u001b[33m (\u001b[m\u001b[1;36mHEAD\u001b[m\u001b[33m)\u001b[m\u001b[m\r\nAuthor: Wilfred Hughes \u001b[m\r\nDate: Sun Mar 20 22:24:21 2022 -0700\u001b[m\r\n\u001b[m\r\n Ignore the trailing newline in source files\u001b[m\r\n \u001b[m\r\n This should have produced a change in output, but it's currently\u001b[m\r\n ignored due to #163.\u001b[m\r\n\u001b[m\r\n"] -[27.118907, "o", "\u001b[1m\u001b[93msrc/main.rs\u001b[39m\u001b[0m --- 1/1 --- Rust\u001b[m\r\n"] -[27.119099, "o", "215 215 }\u001b[m\r\n216 216 \u001b[m\r\n217 217 \u001b[94;3m// TODO: don't replace tab characters inside string literals.\u001b[0m\u001b[m\r\n218 \u001b[92m218 \u001b[39m \u001b[1mlet\u001b[0m \u001b[92;1mmut\u001b[0m lhs_src = \u001b[1mString\u001b[0m::from_utf8_lossy(lhs_bytes)\u001b[m\r\n219 219 .to_string()\u001b[m\r\n220 220 .replace(\u001b[95m'\\t'\u001b[0m, \u001b[95m\" \"\u001b[0m);\u001b[m\r\n221 \u001b[92m221 \u001b[39m \u001b[1mlet\u001b[0m \u001b[92;1mmut\u001b[0m rhs_src = \u001b[1mString\u001b[0m::from_utf8_lossy(rhs_bytes)\u001b[m\r\n222 222 .to_string()\u001b[m\r\n223 223 .replace(\u001b[95m'\\t'\u001b[0m, \u001b[95m\" \"\u001b[0m);\u001b[m\r\n\u001b[2m... \u001b[0m\u001b[92m224 \u001b[39m\u001b[m\r\n\u001b[2m... \u001b[0m\u001b[92m225 \u001b[39m \u001b[92;3m// Ignore the trailing newline, if present.\u001b[0m\u001b[m\r\n\u001b[2m... \u001b[0m\u001b[92m226 \u001b[39m \u001b[92;3m// TODO: highlight if this has changes (#144).\u001b[0m\u001b[m\r\n\u001b[2m... \u001b[0m\u001b[92m227 \u001b[39m \u001b[92;3m// TODO: factor out a string cleaning function.\u001b[0m\u001b[m\r\n:\u001b[K"] -[28.741062, "o", "\r\u001b[K \u001b[KESC\b\b\bESC\u001b[KO\bO\u001b[KB\bB\r\u001b[K\u001b[2m... \u001b[0m\u001b[92m228 \u001b[39m \u001b[92;1mif\u001b[0m \u001b[92mlhs_src\u001b[0m\u001b[92m.\u001b[0m\u001b[92mends_with\u001b[0m\u001b[92;1m(\u001b[0m\u001b[92m'\\n'\u001b[0m\u001b[92;1m)\u001b[0m \u001b[92;1m{\u001b[0m\u001b[m\r\n:\u001b[K"] -[29.058528, "o", "\r\u001b[K \u001b[KESC\b\b\bESC\u001b[KO\bO\u001b[KB\bB\r\u001b[K\u001b[2m... \u001b[0m\u001b[92m229 \u001b[39m \u001b[92mlhs_src\u001b[0m\u001b[92m.\u001b[0m\u001b[92mpop\u001b[0m\u001b[92;1m(\u001b[0m\u001b[92;1m)\u001b[0m\u001b[92m;\u001b[0m\u001b[m\r\n:\u001b[K"] -[29.36318, "o", "\r\u001b[K \u001b[KESC\b\b\bESC\u001b[KO\bO\u001b[KB\bB\r\u001b[K\u001b[2m... \u001b[0m\u001b[92m230 \u001b[39m \u001b[92;1m}\u001b[0m\u001b[m\r\n:\u001b[K"] -[29.610836, "o", "\r\u001b[K \u001b[KESC\b\b\bESC\u001b[KO\bO\u001b[KB\bB\r\u001b[K\u001b[2m... \u001b[0m\u001b[92m231 \u001b[39m \u001b[92;1mif\u001b[0m \u001b[92mrhs_src\u001b[0m\u001b[92m.\u001b[0m\u001b[92mends_with\u001b[0m\u001b[92;1m(\u001b[0m\u001b[92m'\\n'\u001b[0m\u001b[92;1m)\u001b[0m \u001b[92;1m{\u001b[0m\u001b[m\r\n:\u001b[K"] -[29.822642, "o", "\r\u001b[K \u001b[KESC\b\b\bESC\u001b[KO\bO\u001b[KB\bB\r\u001b[K\u001b[2m... \u001b[0m\u001b[92m232 \u001b[39m \u001b[92mrhs_src\u001b[0m\u001b[92m.\u001b[0m\u001b[92mpop\u001b[0m\u001b[92;1m(\u001b[0m\u001b[92;1m)\u001b[0m\u001b[92m;\u001b[0m\u001b[m\r\n:\u001b[K"] -[30.079355, "o", "\r\u001b[K \u001b[KESC\b\b\bESC\u001b[KO\bO\u001b[KB\bB\r\u001b[K"] -[30.079516, "o", "\u001b[2m... \u001b[0m\u001b[92m233 \u001b[39m \u001b[92;1m}\u001b[0m\u001b[m\r\n:\u001b[K"] -[30.350258, "o", "\r\u001b[K \u001b[KESC\b\b\bESC\u001b[KO\bO\u001b[KB\bB\r\u001b[K224 234 \u001b[m\r\n:\u001b[K"] -[30.60035, "o", "\r\u001b[K \u001b[KESC\b\b\bESC\u001b[KO\bO\u001b[KB\bB\r\u001b[K"] -[30.60053, "o", "225 235 \u001b[94;3m// TODO: take a Path directly instead.\u001b[0m\u001b[m\r\n:\u001b[K"] -[30.834164, "o", "\r\u001b[K \u001b[KESC\b\b\bESC\u001b[KO\bO\u001b[KB\bB\r\u001b[K226 236 \u001b[1mlet\u001b[0m path = \u001b[1mPath\u001b[0m::new(\u001b[1m&\u001b[0mdisplay_path);\u001b[m\r\n:\u001b[K"] -[31.07936, "o", "\r\u001b[K \u001b[KESC\b\b\bESC\u001b[KO\bO\u001b[KB\bB\r\u001b[K\u001b[m\r\n:\u001b[K"] -[31.313919, "o", "\r\u001b[K \u001b[KESC\b\b\bESC\u001b[KO\bO\u001b[KB\bB\r\u001b[K\u001b[m\r\n:\u001b[K"] -[31.547364, "o", "\r\u001b[K \u001b[KESC\b\b\bESC\u001b[KO\bO\u001b[KB\bB\r\u001b[K"] -[31.547527, "o", "\u001b[33mcommit c7795111f5767e54205dda13f82c97b2ef5743a1\u001b[m\u001b[m\r\n:\u001b[K"] -[31.795514, "o", "\r\u001b[K \u001b[KESC\b\b\bESC\u001b[KO\bO\u001b[KB\bB\r\u001b[K"] -[31.795633, "o", "Author: Wilfred Hughes \u001b[m\r\n:\u001b[K"] -[32.057382, "o", "\r\u001b[K \u001b[KESC\b\b\bESC\u001b[KO\bO\u001b[KB\bB\r\u001b[K"] -[32.057519, "o", "Date: Sun Mar 20 21:30:17 2022 -0700\u001b[m\r\n:\u001b[K"] -[32.309801, "o", "\r\u001b[K \u001b[KESC\b\b\bESC\u001b[KO\bO\u001b[KB\bB\r\u001b[K\u001b[m\r\n:\u001b[K"] -[32.5347, "o", "\r\u001b[K \u001b[KESC\b\b\bESC\u001b[KO\bO\u001b[KB\bB\r\u001b[K cargo fmt\u001b[m\r\n:\u001b[K"] -[32.783008, "o", "\r\u001b[K \u001b[KESC\b\b\bESC\u001b[KO\bO\u001b[KB\bB\r\u001b[K\u001b[m\r\n:\u001b[K"] -[33.00581, "o", "\r\u001b[K \u001b[KESC\b\b\bESC\u001b[KO\bO\u001b[KB\bB\r\u001b[K\u001b[1m\u001b[93msrc/hunks.rs\u001b[39m\u001b[0m --- 1/1 --- Rust\u001b[m\r\n:\u001b[K"] -[33.255364, "o", "\r\u001b[K \u001b[KESC\b\b\bESC\u001b[KO\bO\u001b[KB\bB\r\u001b[K"] -[33.255475, "o", "No syntactic changes.\u001b[m\r\n:\u001b[K"] -[33.491872, "o", "\r\u001b[K \u001b[KESC\b\b\bESC\u001b[KO\bO\u001b[KB\bB\r\u001b[K\u001b[m\r\n:\u001b[K"] -[33.735072, "o", "\r\u001b[K \u001b[KESC\b\b\bESC\u001b[KO\bO\u001b[KB\bB\r\u001b[K\u001b[m\r\n:\u001b[K"] -[33.977973, "o", "\r\u001b[K \u001b[KESC\b\b\bESC\u001b[KO\bO\u001b[KB\bB\r\u001b[K\u001b[33mcommit 68f3ab2b9243fbbefdb2a5f68a531754cae4c4f7\u001b[m\u001b[m\r\n:\u001b[K"] -[34.225023, "o", "\r\u001b[K \u001b[KESC\b\b\bESC\u001b[KO\bO\u001b[KB\bB\r\u001b[KAuthor: Wilfred Hughes \u001b[m\r\n:\u001b[K"] -[34.466161, "o", "\r\u001b[K \u001b[KESC\b\b\bESC\u001b[KO\bO\u001b[KB\bB\r\u001b[K"] -[34.466259, "o", "Date: Sun Mar 20 19:48:14 2022 -0700\u001b[m\r\n:\u001b[K"] -[34.698357, "o", "\r\u001b[K \u001b[KESC\b\b\bESC\u001b[KO\bO\u001b[KB\bB\r\u001b[K\u001b[m\r\n:\u001b[K"] -[34.941211, "o", "\r\u001b[K \u001b[KESC\b\b\bESC\u001b[KO\bO\u001b[KB\bB\r\u001b[K"] -[34.941426, "o", " Don't consider lines with whitespace to have missing syntax\u001b[m\r\n:\u001b[K"] -[35.174346, "o", "\r\u001b[K \u001b[KESC\b\b\bESC\u001b[KO\bO\u001b[KB\bB\r\u001b[K"] -[35.174501, "o", " \u001b[m\r\n:\u001b[K"] -[35.444257, "o", "\r\u001b[K \u001b[KESC\b\b\bESC\u001b[KO\bO\u001b[KB\bB\r\u001b[K"] -[35.444401, "o", " Fixes #171\u001b[m\r\n:\u001b[K"] -[35.688874, "o", "\r\u001b[K \u001b[KESC\b\b\bESC\u001b[KO\bO\u001b[KB\bB\r\u001b[K\u001b[m\r\n:\u001b[K"] -[35.928177, "o", "\r\u001b[K \u001b[KESC\b\b\bESC\u001b[KO\bO\u001b[KB\bB\r\u001b[K\u001b[1m\u001b[93mCHANGELOG.md\u001b[39m\u001b[0m --- 1/1 --- Text\u001b[m\r\n:\u001b[K"] -[36.159364, "o", "\r\u001b[K \u001b[KESC\b\b\bESC\u001b[KO\bO\u001b[KB\bB\r\u001b[K"] -[36.159518, "o", " 6 6 certain circumstances when a line contained both changed and unchanged\u001b[m\r\n:\u001b[K"] -[36.389208, "o", "\r\u001b[K \u001b[KESC\b\b\bESC\u001b[KO\bO\u001b[KB\bB\r\u001b[K 7 7 parts.\u001b[m\r\n:\u001b[K"] -[36.596542, "o", "\r\u001b[K \u001b[KESC\b\b\bESC\u001b[KO\bO\u001b[KB\bB\r\u001b[K 8 8 \u001b[m\r\n:\u001b[K"] -[36.817159, "o", "\r\u001b[K \u001b[KESC\b\b\bESC\u001b[KO\bO\u001b[KB\bB\r\u001b[K"] -[36.817259, "o", "\u001b[2m . \u001b[0m\u001b[92m 9 \u001b[39m\u001b[92;1mFixed\u001b[0m\u001b[92;1m \u001b[0m\u001b[92;1man\u001b[0m\u001b[92;1m \u001b[0m\u001b[92;1missue\u001b[0m\u001b[92;1m \u001b[0m\u001b[92;1mwhere\u001b[0m\u001b[92;1m \u001b[0m\u001b[92;1mlines\u001b[0m\u001b[92;1m \u001b[0m\u001b[92;1mcontaining\u001b[0m\u001b[92;1m \u001b[0m\u001b[92;1monly\u001b[0m\u001b[92;1m \u001b[0m\u001b[92;1mwhitespace\u001b[0m\u001b[92;1m \u001b[0m\u001b[92;1mwould\u001b[0m\u001b[92;1m \u001b[0m\u001b[92;1mbe\u001b[0m\u001b[m\r\n:\u001b[K"] -[37.046838, "o", "\r\u001b[K \u001b[KESC\b\b\bESC\u001b[KO\bO\u001b[KB\bB\r\u001b[K\u001b[2m . \u001b[0m\u001b[92m10 \u001b[39m\u001b[92;1mhighlighted\u001b[0m\u001b[92;1m \u001b[0m\u001b[92;1min\u001b[0m\u001b[92;1m \u001b[0m\u001b[92;1mpurple\u001b[0m\u001b[92;1m.\u001b[0m\u001b[m\r\n:\u001b[K"] -[37.31998, "o", "\r\u001b[K \u001b[KESC\b\b\bESC\u001b[KO\bO\u001b[KB\bB\r\u001b[K\u001b[2m . \u001b[0m\u001b[92m11 \u001b[39m\u001b[m\r\n:\u001b[K"] -[37.551033, "o", "\r\u001b[K \u001b[KESC\b\b\bESC\u001b[KO\bO\u001b[KB\bB\r\u001b[K 9 12 ### Parsing\u001b[m\r\n:\u001b[K"] -[37.80635, "o", "\r\u001b[K \u001b[KESC\b\b\bESC\u001b[KO\bO\u001b[KB\bB\r\u001b[K10 13 \u001b[m\r\n:\u001b[K"] -[38.029595, "o", "\r\u001b[K \u001b[KESC\b\b\bESC\u001b[KO\bO\u001b[KB\bB\r\u001b[K\u001b[m\r\n:\u001b[K"] -[38.264066, "o", "\r\u001b[K \u001b[KESC\b\b\bESC\u001b[KO\bO\u001b[KB\bB\r\u001b[K\u001b[1m\u001b[93msrc/style.rs\u001b[39m\u001b[0m --- 1/1 --- Rust\u001b[m\r\n:\u001b[K"] -[38.504341, "o", "\r\u001b[K \u001b[KESC\b\b\bESC\u001b[KO\bO\u001b[KB\bB\r\u001b[K"] -[38.504471, "o", "83 use_color: \u001b[1mbool\u001b[0m,\u001b[m\r\n:\u001b[K"] -[38.735321, "o", "\r\u001b[K \u001b[KESC\b\b\bESC\u001b[KO\bO\u001b[KB\bB\r\u001b[K84 styles: \u001b[1m&\u001b[0m[(\u001b[1mSingleLineSpan\u001b[0m, \u001b[1mStyle\u001b[0m)],\u001b[m\r\n:\u001b[K"] -[38.962007, "o", "\r\u001b[K \u001b[KESC\b\b\bESC\u001b[KO\bO\u001b[KB\bB\r\u001b[K85 ) -> \u001b[1mVec\u001b[0m<\u001b[1mString\u001b[0m> {\u001b[m\r\n:\u001b[K"] -[39.208804, "o", "\r\u001b[K \u001b[KESC\b\b\bESC\u001b[KO\bO\u001b[KB\bB\r\u001b[K\u001b[92m86 \u001b[39m \u001b[1mif\u001b[0m styles.is_empty() && !line\u001b[92m.\u001b[0m\u001b[92mtrim\u001b[0m\u001b[92;1m(\u001b[0m\u001b[92;1m)\u001b[0m.is_empty() {\u001b[m\r\n:\u001b[K"] -[39.455321, "o", "\r\u001b[K \u001b[KESC\b\b\bESC\u001b[KO\bO\u001b[KB\bB\r\u001b[K87 \u001b[94;3m// Missing styles is a bug, so highlight in purple to make this obvious.\u001b[0m\u001b[m\r\n:\u001b[K"] -[39.719675, "o", "\r\u001b[K \u001b[KESC\b\b\bESC\u001b[KO\bO\u001b[KB\bB\r\u001b[K"] -[39.719789, "o", "88 \u001b[1mreturn\u001b[0m split_string_by_codepoint(line, max_len)\u001b[m\r\n:\u001b[K"] -[40.000366, "o", "\r\u001b[K \u001b[KESC\b\b\bESC\u001b[KO\bO\u001b[KB\bB\r\u001b[K"] -[40.000537, "o", "89 .into_iter()\u001b[m\r\n:\u001b[K"] -[40.263044, "o", "\r\u001b[K \u001b[KESC\b\b\bESC\u001b[KO\bO\u001b[KB\bB\r\u001b[K\u001b[m\r\n:\u001b[K"] -[40.532331, "o", "\r\u001b[K \u001b[KESC\b\b\bESC\u001b[KO\bO\u001b[KB\bB\r\u001b[K\u001b[m\r\n:\u001b[K"] -[40.799186, "o", "\r\u001b[K \u001b[KESC\b\b\bESC\u001b[KO\bO\u001b[KB\bB\r\u001b[K"] -[40.799289, "o", "\u001b[33mcommit 4563648a9fba93356e9df6be842023ca1c4fb2f4\u001b[m\u001b[m\r\n:\u001b[K"] -[41.05339, "o", "\r\u001b[K \u001b[KESC\b\b\bESC\u001b[KO\bO\u001b[KB\bB\r\u001b[K"] -[41.053535, "o", "Author: Wilfred Hughes \u001b[m\r\n:\u001b[K"] -[41.30637, "o", "\r\u001b[K \u001b[KESC\b\b\bESC\u001b[KO\bO\u001b[KB\bB\r\u001b[K"] -[41.306496, "o", "Date: Sun Mar 20 15:17:32 2022 -0700\u001b[m\r\n:\u001b[K"] -[41.59527, "o", "\r\u001b[K \u001b[KESC\b\b\bESC\u001b[KO\bO\u001b[KB\bB\r\u001b[K\u001b[m\r\n:\u001b[K"] -[41.874913, "o", "\r\u001b[K \u001b[KESC\b\b\bESC\u001b[KO\bO\u001b[KB\bB\r\u001b[K Clarify ChangeKind helper method name\u001b[m\r\n:\u001b[K"] -[42.123997, "o", "\r\u001b[K \u001b[KESC\b\b\bESC\u001b[KO\bO\u001b[KB\bB\r\u001b[K\u001b[m\r\n:\u001b[K"] -[42.406332, "o", "\r\u001b[K \u001b[KESC\b\b\bESC\u001b[KO\bO\u001b[KB\bB\r\u001b[K"] -[42.40648, "o", "\u001b[1m\u001b[93msrc/hunks.rs\u001b[39m\u001b[0m --- 1/2 --- Rust\u001b[m\r\n:\u001b[K"] -[42.673176, "o", "\r\u001b[K \u001b[KESC\b\b\bESC\u001b[KO\bO\u001b[KB\bB\r\u001b[K467 \u001b[1mloop\u001b[0m { 467 \u001b[1mloop\u001b[0m { \u001b[m\r\n:\u001b[K"] -[42.936558, "o", "\r\u001b[K \u001b[KESC\b\b\bESC\u001b[KO\bO\u001b[KB\bB\r\u001b[K"] -[42.936738, "o", "468 \u001b[1mmatch\u001b[0m (lhs_iter.peek(), rhs_iter.peek()) { 468 \u001b[1mmatch\u001b[0m (lhs_iter.peek(), rhs_iter.peek()) { \u001b[m\r\n:\u001b[K"] -[43.187389, "o", "\r\u001b[K \u001b[KESC\b\b\bESC\u001b[KO\bO\u001b[KB\bB\r\u001b[K"] -[43.187461, "o", "469 (Some(lhs_mp), Some(rhs_mp)) 469 (Some(lhs_mp), Some(rhs_mp)) \u001b[m\r\n:\u001b[K"] -[43.439206, "o", "\r\u001b[K \u001b[KESC\b\b\bESC\u001b[KO\bO\u001b[KB\bB\r\u001b[K\u001b[91m470 \u001b[39m \u001b[1mif\u001b[0m !lhs_mp.kind.\u001b[91mis_change\u001b[0m() && !rhs_mp.kind.\u001b[91mis\u001b[0m \u001b[92m470 \u001b[39m \u001b[1mif\u001b[0m !lhs_mp.kind.\u001b[92mis_novel\u001b[0m() && !rhs_mp.kind.\u001b[92mis_\u001b[0m\u001b[m\r\n:\u001b[K"] -[43.756317, "o", "\r\u001b[K \u001b[KESC\b\b\bESC\u001b[KO\bO\u001b[KB\bB\r\u001b[K"] -[43.756474, "o", "\u001b[91m\u001b[2m... \u001b[0m\u001b[39m\u001b[91m_change\u001b[0m() => \u001b[92m\u001b[2m... \u001b[0m\u001b[39m\u001b[92mnovel\u001b[0m() => \u001b[m\r\n:\u001b[K"] -[44.023372, "o", "\r\u001b[K \u001b[KESC\b\b\bESC\u001b[KO\bO\u001b[KB\bB\r\u001b[K"] -[44.023425, "o", "471 { 471 { \u001b[m\r\n:\u001b[K"] -[44.289699, "o", "\r\u001b[K \u001b[KESC\b\b\bESC\u001b[KO\bO\u001b[KB\bB\r\u001b[K"] -[44.289782, "o", "472 res.append(\u001b[1m&\u001b[0m\u001b[1mmut\u001b[0m novel_section_in_order( 472 res.append(\u001b[1m&\u001b[0m\u001b[1mmut\u001b[0m novel_section_in_order( \u001b[m\r\n:\u001b[K"] -[44.560326, "o", "\r\u001b[K \u001b[KESC\b\b\bESC\u001b[KO\bO\u001b[KB\bB\r\u001b[K"] -[44.560452, "o", "473 \u001b[1m&\u001b[0mlhs_section, 473 \u001b[1m&\u001b[0mlhs_section, \u001b[m\r\n:\u001b[K"] -[44.813655, "o", "\r\u001b[K \u001b[KESC\b\b\bESC\u001b[KO\bO\u001b[KB\bB\r\u001b[K"] -[44.813687, "o", "\u001b[m\r\n:\u001b[K"] -[45.078314, "o", "\r\u001b[K \u001b[KESC\b\b\bESC\u001b[KO\bO\u001b[KB\bB\r\u001b[K\u001b[1m\u001b[93msrc/hunks.rs\u001b[39m\u001b[0m --- 2/2 --- Rust\u001b[m\r\n:\u001b[K"] -[45.34377, "o", "\r\u001b[K \u001b[KESC\b\b\bESC\u001b[KO\bO\u001b[KB\bB\r\u001b[K485 lhs_iter.next(); 485 lhs_iter.next(); \u001b[m\r\n:\u001b[K"] -[45.734703, "o", "\r\u001b[K \u001b[KESC\b\b\bESC\u001b[KO\bO\u001b[KB\bB\r\u001b[K486 rhs_iter.next(); 486 rhs_iter.next(); \u001b[m\r\n:\u001b[K"] -[45.978713, "o", "\r\u001b[K \u001b[KESC\b\b\bESC\u001b[KO\bO\u001b[KB\bB\r\u001b[K"] -[45.978757, "o", "487 } 487 } \u001b[m\r\n:\u001b[K"] -[46.300028, "o", "\r\u001b[K \u001b[KESC\b\b\bESC\u001b[KO\bO\u001b[KB\bB\r\u001b[K\u001b[91m488 \u001b[39m (Some(lhs_mp), _) \u001b[1mif\u001b[0m lhs_mp.kind.\u001b[91mis_change\u001b[0m() => { \u001b[92m488 \u001b[39m (Some(lhs_mp), _) \u001b[1mif\u001b[0m lhs_mp.kind.\u001b[92mis_novel\u001b[0m() => { \u001b[m\r\n:\u001b[K"] -[46.584687, "o", "\r\u001b[K \u001b[KESC\b\b\bESC\u001b[KO\bO\u001b[KB\bB\r\u001b[K"] -[46.584758, "o", "489 lhs_section.push(lhs_mp); 489 lhs_section.push(lhs_mp); \u001b[m\r\n:\u001b[K"] -[46.920832, "o", "\r\u001b[K \u001b[KESC\b\b\bESC\u001b[KO\bO\u001b[KB\bB\r\u001b[K"] -[46.920879, "o", "490 lhs_iter.next(); 490 lhs_iter.next(); \u001b[m\r\n:\u001b[K"] -[47.192163, "o", "\r\u001b[K \u001b[KESC\b\b\bESC\u001b[KO\bO\u001b[KB\bB\r\u001b[K491 } 491 } \u001b[m\r\n:\u001b[K"] -[47.505025, "o", "\r\u001b[K \u001b[KESC\b\b\bESC\u001b[KO\bO\u001b[KB\bB\r\u001b[K\u001b[91m492 \u001b[39m (_, Some(rhs_mp)) \u001b[1mif\u001b[0m rhs_mp.kind.\u001b[91mis_change\u001b[0m() => { \u001b[92m492 \u001b[39m (_, Some(rhs_mp)) \u001b[1mif\u001b[0m rhs_mp.kind.\u001b[92mis_novel\u001b[0m() => { \u001b[m\r\n:\u001b[K"] -[47.947911, "o", "\r\u001b[K \u001b[KESC\b\b\bESC\u001b[KO\bO\u001b[KB\bB\r\u001b[K493 rhs_section.push(rhs_mp); 493 rhs_section.push(rhs_mp); \u001b[m\r\n:\u001b[K"] -[48.219369, "o", "\r\u001b[K \u001b[KESC\b\b\bESC\u001b[KO\bO\u001b[KB\bB\r\u001b[K"] -[48.219504, "o", "494 rhs_iter.next(); 494 rhs_iter.next(); \u001b[m\r\n:\u001b[K"] -[48.511357, "o", "\r\u001b[K \u001b[KESC\b\b\bESC\u001b[KO\bO\u001b[KB\bB\r\u001b[K495 } 495 } \u001b[m\r\n:\u001b[K"] -[48.811117, "o", "\r\u001b[K \u001b[KESC\b\b\bESC\u001b[KO\bO\u001b[KB\bB\r\u001b[K\u001b[m\r\n:\u001b[K"] -[49.116431, "o", "\r\u001b[K \u001b[KESC\b\b\bESC\u001b[KO\bO\u001b[KB\bB\r\u001b[K"] -[49.116552, "o", "\u001b[1m\u001b[93msrc/line_parser.rs\u001b[39m\u001b[0m --- 1/2 --- Rust\u001b[m\r\n:\u001b[K"] -[49.900367, "o", "\r\u001b[K \u001b[KESC\b\b\bESC\u001b[KO\bO\u001b[KB\bB\r\u001b[K"] -[49.900419, "o", "257 \u001b[1mlet\u001b[0m positions = change_positions(\u001b[95m\"foo\"\u001b[0m, \u001b[95m\"foo\"\u001b[0m); 257 \u001b[1mlet\u001b[0m positions = change_positions(\u001b[95m\"foo\"\u001b[0m, \u001b[95m\"foo\"\u001b[0m); \u001b[m\r\n:\u001b[K"] -[50.151024, "o", "\r\u001b[K \u001b[KESC\b\b\bESC\u001b[KO\bO\u001b[KB\bB\r\u001b[K258 258 \u001b[m\r\n:\u001b[K"] -[50.418958, "o", "\r\u001b[K \u001b[KESC\b\b\bESC\u001b[KO\bO\u001b[KB\bB\r\u001b[K259 assert_eq!(positions.len(), \u001b[1m1\u001b[0m); 259 assert_eq!(positions.len(), \u001b[1m1\u001b[0m); \u001b[m\r\n:\u001b[K"] -[50.776112, "o", "\r\u001b[K \u001b[KESC\b\b\bESC\u001b[KO\bO\u001b[KB\bB\r\u001b[K\u001b[91m260 \u001b[39m assert!(!positions[\u001b[1m0\u001b[0m].kind.\u001b[91mis_change\u001b[0m()); \u001b[92m260 \u001b[39m assert!(!positions[\u001b[1m0\u001b[0m].kind.\u001b[92mis_novel\u001b[0m()); \u001b[m\r\n:\u001b[K"] -[51.087847, "o", "\r\u001b[K \u001b[KESC\b\b\bESC\u001b[KO\bO\u001b[KB\bB\r\u001b[K261 } 261 } \u001b[m\r\n:\u001b[K"] -[51.368352, "o", "\r\u001b[K \u001b[KESC\b\b\bESC\u001b[KO\bO\u001b[KB\bB\r\u001b[K"] -[51.368527, "o", "262 262 \u001b[m\r\n:\u001b[K"] -[51.846789, "o", "\r\u001b[K \u001b[KESC\b\b\bESC\u001b[KO\bO\u001b[KB\bB\r\u001b[K263 #[test] 263 #[test] \u001b[m\r\n:\u001b[K"] -[52.220319, "o", "\r\u001b[K \u001b[KESC\b\b\bESC\u001b[KO\bO\u001b[KB\bB\r\u001b[K"] -[52.220412, "o", "\u001b[m\r\n:\u001b[K"] -[52.529333, "o", "\r\u001b[K \u001b[KESC\b\b\bESC\u001b[KO\bO\u001b[KB\bB\r\u001b[K"] -[52.529464, "o", "\u001b[1m\u001b[93msrc/line_parser.rs\u001b[39m\u001b[0m --- 2/2 --- Rust\u001b[m\r\n:\u001b[K"] -[53.277786, "o", "\r\u001b[K \u001b[KESC\b\b\bESC\u001b[KO\bO\u001b[KB\bB\r\u001b[K"] -[53.277922, "o", "266 \u001b[94;3m// be treated as a change. We're doing a line-based di\u001b[0m 266 \u001b[94;3m// be treated as a change. We're doing a line-based di\u001b[0m\u001b[m\r\n:\u001b[K"] -[53.580018, "o", "\r\u001b[K \u001b[KESC\b\b\bESC\u001b[KO\bO\u001b[KB\bB\r\u001b[K\u001b[2m... \u001b[0m\u001b[94;3mff and\u001b[0m \u001b[2m... \u001b[0m\u001b[94;3mff and\u001b[0m \u001b[m\r\n:\u001b[K"] -[53.86212, "o", "\r\u001b[K \u001b[KESC\b\b\bESC\u001b[KO\bO\u001b[KB\bB\r\u001b[K"] -[53.86232, "o", "267 \u001b[94;3m// the lines are different.\u001b[0m 267 \u001b[94;3m// the lines are different.\u001b[0m \u001b[m\r\n:\u001b[K"] -[54.144105, "o", "\r\u001b[K \u001b[KESC\b\b\bESC\u001b[KO\bO\u001b[KB\bB\r\u001b[K"] -[54.144228, "o", "268 \u001b[1mlet\u001b[0m positions = change_positions(\u001b[95m\"foo\"\u001b[0m, \u001b[95m\" foo\"\u001b[0m); 268 \u001b[1mlet\u001b[0m positions = change_positions(\u001b[95m\"foo\"\u001b[0m, \u001b[95m\" foo\"\u001b[0m); \u001b[m\r\n:\u001b[K"] -[54.424201, "o", "\r\u001b[K \u001b[KESC\b\b\bESC\u001b[KO\bO\u001b[KB\bB\r\u001b[K\u001b[91m269 \u001b[39m assert!(positions[\u001b[1m0\u001b[0m].kind.\u001b[91mis_change\u001b[0m()); \u001b[92m269 \u001b[39m assert!(positions[\u001b[1m0\u001b[0m].kind.\u001b[92mis_novel\u001b[0m()); \u001b[m\r\n:\u001b[K"] -[54.721199, "o", "\r\u001b[K \u001b[KESC\b\b\bESC\u001b[KO\bO\u001b[KB\bB\r\u001b[K270 } 270 } \u001b[m\r\n:\u001b[K"] -[55.5252, "o", "\r\u001b[K \u001b[KESC\b\b\bESC\u001b[KO\bO\u001b[KB\bB\r\u001b[K271 271 \u001b[m\r\n:\u001b[K"] -[55.808335, "o", "\r\u001b[K \u001b[KESC\b\b\bESC\u001b[KO\bO\u001b[KB\bB\r\u001b[K"] -[55.808517, "o", "272 #[test] 272 #[test] \u001b[m\r\n:\u001b[K"] -[56.134264, "o", "\r\u001b[K \u001b[KESC\b\b\bESC\u001b[KO\bO\u001b[KB\bB\r\u001b[K"] -[56.134383, "o", "273 \u001b[1mfn\u001b[0m test_no_changes_trailing_newlines() { 273 \u001b[1mfn\u001b[0m test_no_changes_trailing_newlines() { \u001b[m\r\n:\u001b[K"] -[56.488093, "o", "\r\u001b[K \u001b[KESC\b\b\bESC\u001b[KO\bO\u001b[KB\bB\r\u001b[K274 \u001b[1mlet\u001b[0m positions = change_positions(\u001b[95m\"foo\\n\"\u001b[0m, \u001b[95m\"foo\\n\"\u001b[0m); 274 \u001b[1mlet\u001b[0m positions = change_positions(\u001b[95m\"foo\\n\"\u001b[0m, \u001b[95m\"foo\\n\"\u001b[0m); \u001b[m\r\n:\u001b[K"] -[56.771359, "o", "\r\u001b[K \u001b[KESC\b\b\bESC\u001b[KO\bO\u001b[KB\bB\r\u001b[K"] -[56.771495, "o", "275 275 \u001b[m\r\n:\u001b[K"] -[57.0932, "o", "\r\u001b[K \u001b[KESC\b\b\bESC\u001b[KO\bO\u001b[KB\bB\r\u001b[K"] -[57.09332, "o", "276 assert_eq!(positions.len(), \u001b[1m1\u001b[0m); 276 assert_eq!(positions.len(), \u001b[1m1\u001b[0m); \u001b[m\r\n:\u001b[K"] -[57.380651, "o", "\r\u001b[K \u001b[KESC\b\b\bESC\u001b[KO\bO\u001b[KB\bB\r\u001b[K"] -[57.380791, "o", "\u001b[91m277 \u001b[39m assert!(!positions[\u001b[1m0\u001b[0m].kind.\u001b[91mis_change\u001b[0m()); \u001b[92m277 \u001b[39m assert!(!positions[\u001b[1m0\u001b[0m].kind.\u001b[92mis_novel\u001b[0m()); \u001b[m\r\n:\u001b[K"] -[57.676578, "o", "\r\u001b[K \u001b[KESC\b\b\bESC\u001b[KO\bO\u001b[KB\bB\r\u001b[K278 } 278 } \u001b[m\r\n:\u001b[K"] -[57.991349, "o", "\r\u001b[K \u001b[KESC\b\b\bESC\u001b[KO\bO\u001b[KB\bB\r\u001b[K"] -[57.991482, "o", "279 279 \u001b[m\r\n:\u001b[K"] -[58.252298, "o", "\r\u001b[K \u001b[KESC\b\b\bESC\u001b[KO\bO\u001b[KB\bB\r\u001b[K280 #[test] 280 #[test] \u001b[m\r\n:\u001b[K"] -[58.575488, "o", "\r\u001b[K \u001b[KESC\b\b\bESC\u001b[KO\bO\u001b[KB\bB\r\u001b[K281 \u001b[1mfn\u001b[0m test_novel_lhs_trailing_newlines() { 281 \u001b[1mfn\u001b[0m test_novel_lhs_trailing_newlines() { \u001b[m\r\n:\u001b[K"] -[58.817923, "o", "\r\u001b[K \u001b[KESC\b\b\bESC\u001b[KO\bO\u001b[KB\bB\r\u001b[K"] -[58.818047, "o", "282 \u001b[1mlet\u001b[0m positions = change_positions(\u001b[95m\"foo\\n\"\u001b[0m, \u001b[95m\"\"\u001b[0m); 282 \u001b[1mlet\u001b[0m positions = change_positions(\u001b[95m\"foo\\n\"\u001b[0m, \u001b[95m\"\"\u001b[0m); \u001b[m\r\n:\u001b[K"] -[59.083857, "o", "\r\u001b[K \u001b[KESC\b\b\bESC\u001b[KO\bO\u001b[KB\bB\r\u001b[K283 283 \u001b[m\r\n:\u001b[K"] -[59.373054, "o", "\r\u001b[K \u001b[KESC\b\b\bESC\u001b[KO\bO\u001b[KB\bB\r\u001b[K284 assert_eq!(positions.len(), \u001b[1m1\u001b[0m); 284 assert_eq!(positions.len(), \u001b[1m1\u001b[0m); \u001b[m\r\n:\u001b[K"] -[59.651963, "o", "\r\u001b[K \u001b[KESC\b\b\bESC\u001b[KO\bO\u001b[KB\bB\r\u001b[K\u001b[91m285 \u001b[39m assert!(positions[\u001b[1m0\u001b[0m].kind.\u001b[91mis_change\u001b[0m()); \u001b[92m285 \u001b[39m assert!(positions[\u001b[1m0\u001b[0m].kind.\u001b[92mis_novel\u001b[0m()); \u001b[m\r\n:\u001b[K"] -[59.890377, "o", "\r\u001b[K \u001b[KESC\b\b\bESC\u001b[KO\bO\u001b[KB\bB\r\u001b[K"] -[59.890501, "o", "286 } 286 } \u001b[m\r\n:\u001b[K"] -[60.155924, "o", "\r\u001b[K \u001b[KESC\b\b\bESC\u001b[KO\bO\u001b[KB\bB\r\u001b[K287 287 \u001b[m\r\n:\u001b[K"] -[60.399366, "o", "\r\u001b[K \u001b[KESC\b\b\bESC\u001b[KO\bO\u001b[KB\bB\r\u001b[K"] -[60.399523, "o", "288 #[test] 288 #[test] \u001b[m\r\n:\u001b[K"] -[60.648342, "o", "\r\u001b[K \u001b[KESC\b\b\bESC\u001b[KO\bO\u001b[KB\bB\r\u001b[K"] -[60.648484, "o", "289 \u001b[1mfn\u001b[0m test_positions_novel_lhs() { 289 \u001b[1mfn\u001b[0m test_positions_novel_lhs() { \u001b[m\r\n:\u001b[K"] -[60.914846, "o", "\r\u001b[K \u001b[KESC\b\b\bESC\u001b[KO\bO\u001b[KB\bB\r\u001b[K290 \u001b[1mlet\u001b[0m positions = change_positions(\u001b[95m\"foo\"\u001b[0m, \u001b[95m\"\"\u001b[0m); 290 \u001b[1mlet\u001b[0m positions = change_positions(\u001b[95m\"foo\"\u001b[0m, \u001b[95m\"\"\u001b[0m); \u001b[m\r\n:\u001b[K"] -[61.196992, "o", "\r\u001b[K \u001b[KESC\b\b\bESC\u001b[KO\bO\u001b[KB\bB\r\u001b[K"] -[61.197123, "o", "291 291 \u001b[m\r\n:\u001b[K"] -[61.43917, "o", "\r\u001b[K \u001b[KESC\b\b\bESC\u001b[KO\bO\u001b[KB\bB\r\u001b[K292 assert_eq!(positions.len(), \u001b[1m1\u001b[0m); 292 assert_eq!(positions.len(), \u001b[1m1\u001b[0m); \u001b[m\r\n:\u001b[K"] -[61.678722, "o", "\r\u001b[K \u001b[KESC\b\b\bESC\u001b[KO\bO\u001b[KB\bB\r\u001b[K"] -[61.678806, "o", "\u001b[91m293 \u001b[39m assert!(positions[\u001b[1m0\u001b[0m].kind.\u001b[91mis_change\u001b[0m()); \u001b[92m293 \u001b[39m assert!(positions[\u001b[1m0\u001b[0m].kind.\u001b[92mis_novel\u001b[0m()); \u001b[m\r\n:\u001b[K"] -[61.934891, "o", "\r\u001b[K \u001b[KESC\b\b\bESC\u001b[KO\bO\u001b[KB\bB\r\u001b[K"] -[61.935035, "o", "294 } 294 } \u001b[m\r\n:\u001b[K"] -[62.191021, "o", "\r\u001b[K \u001b[KESC\b\b\bESC\u001b[KO\bO\u001b[KB\bB\r\u001b[K295 } 295 } \u001b[m\r\n:\u001b[K"] -[62.428708, "o", "\r\u001b[K \u001b[KESC\b\b\bESC\u001b[KO\bO\u001b[KB\bB\r\u001b[K\u001b[m\r\n:\u001b[K"] -[62.670875, "o", "\r\u001b[K \u001b[KESC\b\b\bESC\u001b[KO\bO\u001b[KB\bB\r\u001b[K"] -[63.441112, "o", "\r\u001b[K\u001b[?1l\u001b>"] -[63.443863, "o", "\u001b[1m\u001b[7m%\u001b[27m\u001b[1m\u001b[0m \r \r"] -[63.444894, "o", "\u001b]7;file:///home/wilfred/projects/difftastic\u001b\\"] -[63.444993, "o", "\r\u001b[0m\u001b[27m\u001b[24m\u001b[J$ \u001b[K\u001b[?2004h"] -[67.143027, "o", "# Want to learn more? Check out the GitHub repository for installation instructions:"] -[67.375589, "o", "\u001b[?2004l\r\r\n"] -[67.376115, "o", "\u001b[1m\u001b[7m%\u001b[27m\u001b[1m\u001b[0m \r \r"] -[67.376986, "o", "\u001b]7;file:///home/wilfred/projects/difftastic\u001b\\"] -[67.377235, "o", "\r\u001b[0m\u001b[27m\u001b[24m\u001b[J$ \u001b[K\u001b[?2004h"] -[70.297425, "o", "# https://github.com/wilfred/difftastic"] -[70.673514, "o", "\u001b[?2004l\r\r\n"] -[70.673731, "o", "\u001b[1m\u001b[7m%\u001b[27m\u001b[1m\u001b[0m \r \r"] -[70.675, "o", "\u001b]7;file:///home/wilfred/projects/difftastic\u001b\\"] diff --git a/homepage/home_static/style.css b/homepage/home_static/style.css deleted file mode 100644 index d75eacd0f..000000000 --- a/homepage/home_static/style.css +++ /dev/null @@ -1,88 +0,0 @@ -body { - animation: 2s ease-out 0s 1 FadeIn; -} -@keyframes FadeIn { - 0% { - opacity: 0; - } - 100% { - opacity: 1; - } -} - -body { - --bs-body-font-size: 18px; - --bs-border-radius: 0.5rem; -} - -h1 { - font-family: "Fontdiner Swanky", serif; - text-shadow: 5px 5px #1d1b22; -} - -h3 { - line-height: 45px; -} - -/* Constrain container width even more than container-sm. -https://getbootstrap.com/docs/5.3/layout/containers/#how-they-work */ -@media (min-width: 992px) { - .container-sm { - max-width: 960px !important; - } -} - -.card h2 { - padding-bottom: 1rem; -} - -html, -body { - background-color: #2e3436; -} - -/* Colours from Tango theme */ -.red, -code { - color: #ef2929; -} -.green, -a { - color: #8ae234; -} - -.img-wrapper { - width: atuo; - border: var(--bs-card-border-width) solid var(--bs-card-border-color); - border-radius: var(--bs-border-radius); - background-color: #2e3436; -} -.img-wrapper img { - max-width: 100%; -} - -.card-body object { - background-color: #f8f8f2; - border-radius: 25% 25%; - padding: 5px; - box-shadow: 5px 5px #a09fa2; -} - -.github-logo { - margin-right: 5px; - pointer-events: none; -} - -.card-set .card { - border-radius: 0; - border-bottom: 0; -} -.card-set .card:first-child { - border-top-right-radius: var(--bs-card-border-radius); - border-top-left-radius: var(--bs-card-border-radius); -} -.card-set .card:last-child { - border-bottom-right-radius: var(--bs-card-border-radius); - border-bottom-left-radius: var(--bs-card-border-radius); - border-bottom: var(--bs-card-border-width) solid var(--bs-card-border-color); -} diff --git a/homepage/index.html b/homepage/index.html deleted file mode 100644 index b8ff04e5b..000000000 --- a/homepage/index.html +++ /dev/null @@ -1,607 +0,0 @@ - - - - - - - Difftastic, a structural diff - - - - - - - - - - - - - - - -
-

- difftastic -

- -
-

- a structural diff tool that understands syntax -

- -
-
- -
-

- Difftastic is a CLI diff tool that compares files based on their syntax, - not line-by-line. Difftastic produces accurate diffs that are easier for - humans to read. -

- -
-
-
-

- Understand - What Actually Changed -

- -
- screenshot -
-

- Difftastic parses your code with - tree-sitter. Unlike a line-oriented diff, difftastic understands that the - inner expression hasn't changed here. -

-
-
- -
-
-

Ignore Formatting Changes

- -
- screenshot -
-

- Has your code formatter decided to split something over multiple - lines? Difftastic can show what has actually changed. -

-
-
- -
-
-

Visualise Wrapping Changes

- -
- screenshot -
-

- Have you added a wrapper? Difftastic can match the delimiters - exactly. -

- -
- screenshot -
-

- Even if you change the inner content, difftastic can still show - you the additional wrapper. -

-
-
- -
-
-

- Real - Line Numbers -

- -
- screenshot -
-

- Do you know how to read - @@ -5,6 +5,7 @@ syntax? Difftastic shows the actual - line numbers from your files, both before and after. -

-
-
-
- -
-
-

60 Second Demo

- -
-
-
- - -
-
-
-

Programming Languages

- -
-
- - -

C++

-
- -
- -
-

C#

-
-
- -
- - -
-

Clojure

-
-
- -
- - -
-

Dart

-
-
- -
- - -
-

Erlang

-
-
- -
- - -
-

Go

-
-
- -
- - -
-

Haskell

-
-
- -
- - -
-

Java

-
-
- -
- - -
-

JavaScript

-
-
- -
- - -
-

Kotlin

-
-
- -
- - -
-

Lisp

-
-
- -
- - -
-

Lua

-
-
- -
- - -
-

OCaml

-
-
- -
- - -
-

PHP

-
-
- -
- -
-

Python

-
-
- -
- - -
-

R

-
-
- -
- - -
-

Ruby

-
-
- -
- - -
-

Rust

-
-
- -
- - -
-

Scala

-
-
- -
- - -
-

TypeScript

-
-
- - -
- -

- And more! See the full - list of supported languages - in the manual. -

-
-
- -
-
-

File Formats

- -
-
- - - -
-

HCL

-
-
- -
- - -
-

HTML

-
-
- -
- - -
-

JSON

-
-
- -
- - -
-

YAML

-
-
- -
- -

- And even more! See the full - list of supported file formats - in the manual. -

-
-
-
- -
-
-

Works With Git

-
- screenshot -
-

- See the - git configuration - instructions in the manual. -

-
-
- -
-
-

Fully Open Source

-

- Difftastic is - MIT licensed. Download it, modify it, share it with your friends! -

-
-
- -

- Made with Emacs and coffee by - Wilfred Hughes. -

-
- - - - - - - diff --git a/justfile b/justfile index ec4bd6105..bf52a8c24 100644 --- a/justfile +++ b/justfile @@ -1,38 +1,15 @@ default: @just --list -# Build and serve the manual. -doc: - cd manual && mdbook serve --open - # Create a git tag and push it, to trigger a release on GitHub actions. release: #!/bin/bash set -ex - VERSION=$(cargo metadata --format-version=1 | jq -r '.packages | .[] | select(.name == "difftastic") | .version') + VERSION=$(cargo metadata --format-version=1 --no-deps | jq -r '.packages | .[] | select(.name == "difftastic") | .version') git tag $VERSION - git push --tags - - cargo set-version --bump minor - -# Serve the homepage locally. -home: - echo "http://localhost:8080" - cd homepage && python -m http.server 8080 - -# Generate release notes for the currently unreleased version. -rel_notes: - #!/bin/bash - - echo -e "Difftastic is a structural diff tool that understands syntax. See [the manual](https://difftastic.wilfred.me.uk/introduction.html) to get started, and [the changelog](https://github.com/Wilfred/difftastic/blob/master/CHANGELOG.md) for historical changes.\n" - - rg --max-count 1 -B 9999 "released " CHANGELOG.md | tail -n +3 | head -n -2 | awk 'BEGIN{RS="\n\n"; ORS="\n\n"} {gsub(/\n/, " "); print}' - -# Regenerate the man page difft.1 from diff.1.md. -man: - pandoc --standalone --to man difft.1.md -o difft.1 + git push origin $VERSION # Run perf stat on baseline test files and save results. perf: @@ -44,10 +21,10 @@ perf: TIMESTAMP=$(date '+%Y-%m-%d_%H-%M-%S') OUTFILE="perf_baseline_${TIMESTAMP}.txt" - echo '$ perf stat ./target/release/difft sample_files/typing_1.ml sample_files/typing_2.ml >/dev/null' >> "$OUTFILE" - perf stat ./target/release/difft sample_files/typing_1.ml sample_files/typing_2.ml >/dev/null 2>> "$OUTFILE" + echo '$ perf stat ./target/release/diffr sample_files/typing_1.ml sample_files/typing_2.ml >/dev/null' >> "$OUTFILE" + perf stat ./target/release/diffr sample_files/typing_1.ml sample_files/typing_2.ml >/dev/null 2>> "$OUTFILE" - echo '$ perf stat ./target/release/difft sample_files/slow_1.rs sample_files/slow_2.rs >/dev/null' >> "$OUTFILE" - perf stat ./target/release/difft sample_files/slow_1.rs sample_files/slow_2.rs >/dev/null 2>> "$OUTFILE" + echo '$ perf stat ./target/release/diffr sample_files/slow_1.rs sample_files/slow_2.rs >/dev/null' >> "$OUTFILE" + perf stat ./target/release/diffr sample_files/slow_1.rs sample_files/slow_2.rs >/dev/null 2>> "$OUTFILE" echo "Results written to $OUTFILE" diff --git a/manual/.gitignore b/manual/.gitignore deleted file mode 100644 index 7585238ef..000000000 --- a/manual/.gitignore +++ /dev/null @@ -1 +0,0 @@ -book diff --git a/manual/book.toml b/manual/book.toml deleted file mode 100644 index 8c15ea0dd..000000000 --- a/manual/book.toml +++ /dev/null @@ -1,20 +0,0 @@ -[book] -authors = ["Wilfred Hughes"] -language = "en" -src = "src" -title = "Difftastic Manual" -description = "The manual for difftastic, the structural diff tool" - -[output.html] -git-repository-url = "https://github.com/wilfred/difftastic" -edit-url-template = "https://github.com/wilfred/difftastic/edit/master/manual/{path}" - -[output.html.redirect] -"/getting_started.html" = "./installation.html" -"/upstream_parsers.html" = "/languages_supported.html" - -[output.html.playground] -copyable = false - -[preprocessor.replace-version-placeholder] -command = "./replace_version_placeholder.sh" diff --git a/manual/replace_version_placeholder.sh b/manual/replace_version_placeholder.sh deleted file mode 100755 index 69a99b512..000000000 --- a/manual/replace_version_placeholder.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/bash - -DFT_VERSION=$(cargo read-manifest | jq -r .version) - -jq --arg version "$DFT_VERSION" '.[1] | walk(if type == "string" then gsub("DFT_VERSION_HERE"; $version) else . end)' diff --git a/manual/src/SUMMARY.md b/manual/src/SUMMARY.md deleted file mode 100644 index f74cdcee9..000000000 --- a/manual/src/SUMMARY.md +++ /dev/null @@ -1,23 +0,0 @@ -# Summary - -- [Introduction](./introduction.md) -- [Installation](./installation.md) - - [From Source](./from_source.md) - - [Packaging Difftastic](./packaging_difftastic.md) -- [Usage](./usage.md) - - [Git](./git.md) - - [Mercurial](./mercurial.md) - - [Fossil](./fossil.md) - - [Jujutsu](./jj.md) -- [Languages Supported](./languages_supported.md) - - [Language Detection](./language_detection.md) -- [Internals: Parsing](./parsing.md) -- [Internals: Diffing](./diffing.md) - - [Tricky Cases](./tricky_cases.md) -- [Contributing](./contributing.md) - - [Adding A Parser](./adding_a_parser.md) - - [Parser Vendoring](./parser_vendoring.md) - - [Profiling](./profiling.md) -- [Glossary](./glossary.md) -- [Alternative Projects](./alternative_projects.md) - - [Tree Diffing](./tree_diffing.md) diff --git a/manual/src/adding_a_parser.md b/manual/src/adding_a_parser.md deleted file mode 100644 index f7503f870..000000000 --- a/manual/src/adding_a_parser.md +++ /dev/null @@ -1,120 +0,0 @@ -# Adding A Parser - -## Finding a parser - -New parsers for difftastic must be reasonably complete and maintained. - -There are many tree-sitter parsers available, and the tree-sitter -website includes [a list of some well-known -parsers](https://tree-sitter.github.io/tree-sitter/#available-parsers). - -## Add the source code - -Ideally, the parser should be available as a Rust crate on crates.io. -If that's the case, add it to `Cargo.toml` in the alphabetically sorted list -of parser dependencies. For instance: -``` -tree-sitter-json = "0.24.8" -``` -Otherwise, it is possible to [vendor the parser in difftastic's source code](./parser_vendoring.md), -but this should only be used as a last resort. - -## Configure parsing - -Add an entry to `tree_sitter_parser.rs` for your language. - -```rust -Json => { - let language_fn = tree_sitter_json::LANGUAGE; - let language = tree_sitter::Language::new(language_fn); - - TreeSitterConfig { - language, - atom_nodes: vec!["string"].into_iter().collect(), - delimiter_tokens: vec![("{", "}"), ("[", "]")], - highlight_query: ts::Query::new(language, tree_sitter_json::HIGHLIGHTS_QUERY) - .unwrap(), - sub_languages: vec![], - } -} -``` - -If the Rust crate does not include a `HIGHLIGHTS_QUERY`, then you need to include -it from a file instead, with -``` -include_str!("../../vendored_parsers/highlights/json.scm") -``` -Many parser repositories include a highlights query in the repository without -exposing it in the Rust crate. In that case you can include it as -`vendored_parsers/highlights/json.scm` in the repository. - -`atom_nodes` is a list of tree-sitter node names that should be -treated as atoms even though the nodes have children. This is common -for things like string literals or interpolated strings, where the -node might have children for the opening and closing quote. - -If you don't set `atom_nodes`, you may notice added/removed content -shown in white. This is usually a sign that a child node should have -its parent treated as an atom. - -`delimiter_tokens` are delimiters that difftastic stores on -the enclosing list node. This allows difftastic to distinguish -delimiter tokens from other punctuation in the language. - -If you don't set `delimiter_tokens`, difftastic will consider the -tokens in isolation, and may think that a `(` was added but the `)` -was unchanged. - -You can use `difft --dump-ts foo.json` to see the results of the -tree-sitter parser, and `difft --dump-syntax foo.json` to confirm that -you've set atoms and delimiters correctly. - -## Configure language detection - -Update `language_name` in `guess_language.rs` to detect your new -language. Insert a match arm like: - -``` -Json => "json", -``` - -There may also be file names or shebangs associated with your language; configure those -by adapting the `language_globs`, `from_emacs_mode_header` and `from_shebang` functions -in that file. -[GitHub's linguist definitions](https://github.com/github/linguist/blob/master/lib/linguist/languages.yml) -are a useful source of common file extensions. - -## Test It - -Search GitHub for a popular repository in your target language -([example -search](https://github.com/search?l=&o=desc&q=stars%3A%3E100+language%3AJSON&s=stars&type=repositories)) -and confirm that git history looks sensible with difftastic. - -## Add a regression test - -Finally, add a regression test for your language. This ensures that -the output for your test file doesn't change unexpectedly. - -Regression test files live in `sample_files/` and have the form -`foo_1.abc` and `foo_2.abc`. - -``` -$ nano simple_1.json -$ nano simple_2.json -``` - -Run the regression test script and update the `.expected` file. - -``` -$ ./sample_files/compare_all.sh -$ cp sample_files/compare.result sample_files/compare.expected -``` - -## Maintenance - -To update a parser that is already imported, use `git subtree pull`. - -``` -$ git subtree pull --prefix=vendored_parsers/tree-sitter-json git@github.com:tree-sitter/tree-sitter-json.git master -``` diff --git a/manual/src/alternative_projects.md b/manual/src/alternative_projects.md deleted file mode 100644 index 61cd933f0..000000000 --- a/manual/src/alternative_projects.md +++ /dev/null @@ -1,5 +0,0 @@ -# Alternative Projects - -Many different tools exist for diffing files. This section of the -manual discusses the design of other tools that have influenced -difftastic. diff --git a/manual/src/contributing.md b/manual/src/contributing.md deleted file mode 100644 index c4b192d0f..000000000 --- a/manual/src/contributing.md +++ /dev/null @@ -1,94 +0,0 @@ -# Contributing - -## Building - -Install Rust with [rustup](https://rustup.rs/), then clone the code. - -``` -$ git clone git@github.com:Wilfred/difftastic.git -$ cd difftastic -``` - -Difftastic uses [Cargo](https://doc.rust-lang.org/cargo/) for -building. - -``` -$ cargo build -``` - -Debug builds are significantly slower than release builds. For files -with more than fifty lines, it's usually worth using an optimised -build. - -``` -$ cargo build --release -``` - -## Manual - -This website is generated with -[mdbook](https://github.com/rust-lang/mdBook/). mdbook can be -installed with Cargo. - -*Note: difftastic uses an older Rust toolchain version. You have to run `cargo install mdbook` outside of the repository directory. Otherwise, installation fails.* - -``` -$ cargo install mdbook -``` - -You can then use the `mdbook` binary to build and serve the site -locally. - -``` -$ cd manual -$ mdbook serve -``` - -## API Documentation - -You can browse the internal API documentation generated by rustdoc -[here](https://difftastic.wilfred.me.uk/rustdoc/difft/). - -Difftastic's internal docs are not available on docs.rs, as it [does -not support binary crates today](https://github.com/rust-lang/docs.rs/issues/238). - -## Testing - -``` -$ cargo test -``` - -There are also several files in `sample_files/` that you can use. - -The best way to test difftastic is to look at history from a real -project. Set `GIT_EXTERNAL_DIFF` to point to your current build. - -For example, you can run difftastic on its own source code. - -``` -$ GIT_EXTERNAL_DIFF=./target/release/difft git log -p --ext-diff -- src -``` - -## Logging - -Difftastic uses the `pretty_env_logger` library to log some additional -debug information. - -``` -$ DFT_LOG=debug cargo run sample_files/old.jsx sample_files/new.jsx -``` - -See the [`env_logger` -documentation](https://docs.rs/env_logger/latest/env_logger/) for full details. - -## Releasing - -Use Cargo to create a new release, and tag it in git. Difftastic has a -helper script for this: - -``` -$ ./scripts/release.sh -``` - -You can now increment the version in Cargo.toml and add a new entry to -CHANGELOG.md. diff --git a/manual/src/diffing.md b/manual/src/diffing.md deleted file mode 100644 index 1e382ae8d..000000000 --- a/manual/src/diffing.md +++ /dev/null @@ -1,99 +0,0 @@ -# Internals: Diffing - -Difftastic treats diff calculations as a route finding problem on a -directed acyclic graph. - -## Graph Representation - -A vertex in the graph represents a position in two syntax trees. - -The start vertex has both positions pointing to the first syntax node -in both trees. The end vertex has both positions just -after the last syntax node in both trees. - -Consider comparing `A` with `X A`. - -``` -START -+---------------------+ -| Left: A Right: X A | -| ^ ^ | -+---------------------+ - -END -+---------------------+ -| Left: A Right: X A | -| ^ ^| -+---------------------+ -``` - -From the start vertex, we have two options: - -* we can mark the first syntax node on the left as novel, and advance - to the next syntax node on the left (vertex 1 above), or -* we can mark the first syntax node on the right as novel, and advance - to the next syntax node on the right (vertex 2 above). - -``` - START - +---------------------+ - | Left: A Right: X A | - | ^ ^ | - +---------------------+ - / \ - Novel atom L / \ Novel atom R -1 v 2 v -+---------------------+ +---------------------+ -| Left: A Right: X A | | Left: A Right: X A | -| ^ ^ | | ^ ^ | -+---------------------+ +---------------------+ -``` - -Choosing "novel atom R" to vertex 2 will turn out to be the best -choice. From vertex 2, we can see three routes to the end vertex. - -``` - 2 - +---------------------+ - | Left: A Right: X A | - | ^ ^ | - +---------------------+ - / | \ - Novel atom L / | \ Novel atom R - v | v -+---------------------+ | +---------------------+ -| Left: A Right: X A | | | Left: A Right: X A | -| ^ ^ | | | ^ ^| -+---------------------+ | +---------------------+ - | | | - | Novel atom R | Nodes match | Novel atom L - | | | - | END v | - | +---------------------+ | - +-------->| Left: A Right: X A |<---------+ - | ^ ^| - +---------------------+ -``` - -## Comparing Routes - -We assign a cost to each edge. Marking a syntax node as novel is worse -than finding a matching syntax node, so the "novel atom" edge has a -higher cost than the "syntax nodes match" edge. - -The best route is the lowest cost route from the start vertex to the -end vertex. - -## Finding The Best Route - -Difftastic uses Dijkstra's algorithm to find the best (i.e. lowest cost) -route. - -One big advantage of this algorithm is that we don't need to construct -the graph in advance. Constructing the whole graph would require -exponential memory relative to the number of syntax nodes. Instead, -vertex neighbours are constructed as the graph is explored. - -There are lots of resources explaining Dijkstra's algorithm online, -but I particularly recommend the [graph search section of Red Blob -Games](https://www.redblobgames.com/pathfinding/a-star/introduction.html#dijkstra). diff --git a/manual/src/fossil.md b/manual/src/fossil.md deleted file mode 100644 index 08fed24c1..000000000 --- a/manual/src/fossil.md +++ /dev/null @@ -1,29 +0,0 @@ -# Fossil - -[Fossil](https://fossil-scm.org/) supports external `diff` commands by [setting `diff-command`](https://fossil-scm.org/home/help?cmd=diff-command) for the current repository: - -``` -fossil settings diff-command difft -``` - -To use difftastic for all repositories, use `--global`: - -``` -fossil settings diff-command --global difft -``` - -## Skip difftastic on Fossil - -If you set difftastic as Fossil's `diff` command, but you need to use Fossil's internal diff once, use `-i` to skip difftastic once: - -``` -fossil diff -i -``` - -If you want to remove difftastic from one repository (or globally), use `unset`: - -``` -fossil unset diff-command -``` - -`unset` also supports the `--global` flag. diff --git a/manual/src/from_source.md b/manual/src/from_source.md deleted file mode 100644 index cf0aaf115..000000000 --- a/manual/src/from_source.md +++ /dev/null @@ -1,42 +0,0 @@ -# Installing From Source - -## Build Requirements - -Difftastic is written in Rust, so you will need Rust installed. I -recommend [rustup](https://rustup.rs/) to install Rust. Difftastic -requires Rust version 1.85 or later. - -You will also need a C++ compiler that supports C++14. If you're using -GCC, you need at least version 8. - -## Build - -You can download and build [difftastic on -crates.io](https://crates.io/crates/difftastic) with Cargo (which is -part of Rust). - -``` -$ cargo install --locked difftastic -``` - -Difftastic uses the `cc` crate for building C/C++ dependencies. This -allows you to use environment variables `CC` and `CXX` to control the -compiler used (see the [`cc` -docs](https://github.com/alexcrichton/cc-rs#external-configuration-via-environment-variables)). - -See [contributing](./contributing.md) for instructions on debug -builds. - -## (Optional) Install a MIME Database - -If a MIME database is available, difftastic will use it to detect -binary files more accurately. This is the same database used by the -`file` command, so you probably already have it. - -The MIME database path is [specified in the XDG -specification](https://specifications.freedesktop.org/shared-mime-info-spec/0.11/ar01s03.html). The -database should be at one of the following paths: - -* `/usr/share/mime/magic` -* `/usr/local/share/mime/magic` -* `$HOME/.local/share/mime/magic` diff --git a/manual/src/git.md b/manual/src/git.md deleted file mode 100644 index 00adb4dd9..000000000 --- a/manual/src/git.md +++ /dev/null @@ -1,139 +0,0 @@ -# Git - -Difftastic can be used an external diff command in git, allowing -difftastic to be used with any git subcommand. - -> [!WARNING] -> git v2.43.1 and earlier [can -crash](https://github.com/git/git/commit/85a9a63c9268b18b24f25f6a14d6ae9966c3566d) when using an external diff and file permissions have changed. -> -> If you can't upgrade git, use the `difftool` configuration described below. - - - -## One-Off Usage - -You can set the `diff.external` configuration option when running `git -diff`, or set the -[`GIT_EXTERNAL_DIFF`](https://git-scm.com/docs/diff-config#Documentation/diff-config.txt-diffexternal) environment variable. - -View uncommitted changes with difftastic: - -``` -$ git -c diff.external=difft diff -``` - -Other git commands also require the `--ext-diff` argument in order to -use `diff.external`. - -View changes from the most recent commit with difftastic: - -``` -$ git -c diff.external=difft show --ext-diff -``` - -View changes from recent commits on the current branch with -difftastic: - -``` -$ git -c diff.external=difft log -p --ext-diff -``` - -## Regular Usage - -If you like difftastic, we recommend that you configure git aliases -so you can use difftastic more easily. - -```ini -[alias] - # Difftastic aliases, so `git dlog -p` is `git log -p` - # with difftastic and likewise for the other subcommands. - dlog = -c diff.external=difft log --ext-diff - dshow = -c diff.external=difft show --ext-diff - ddiff = -c diff.external=difft diff -``` - -The author likes the following additional aliases to reduce typing: - -```ini -[alias] - # `git log` with patches shown with difftastic. - dl = -c diff.external=difft log -p --ext-diff - - # Show the most recent commit with difftastic. - ds = -c diff.external=difft show --ext-diff - - # `git diff` with difftastic. - dft = -c diff.external=difft diff -``` - -## Difftastic By Default - -If you want to use difftastic as your default diff tool, add the -following to your `~/.gitconfig`. - -```ini -[diff] - external = difft -``` - -This changes `git diff` to use difftastic, and other commands now only -require `--ext-diff`. - -``` -$ git diff -$ git show --ext-diff -$ git log -p --ext-diff -``` - -If you've configured difftastic as the default diff tool, you can -opt-out for an individual command with `--no-ext-diff`. - -``` -$ git diff --no-ext-diff -``` - -## Difftool - -Git also has a [difftool -feature](https://git-scm.com/docs/git-difftool) which allows users to -invoke CLI or GUI comparison tools. - -For best results, we recommend using `-c diff.external=difft` as -described above. Git passes more information to the external diff, -including file permission changes and rename information, so -difftastic can show more information. - -To define a difftool named `difftastic`, add the following to your -`~/.gitconfig`. - -```ini -[difftool "difftastic"] - # See `man git-difftool` for a description of MERGED, LOCAL and REMOTE. - cmd = difft "$MERGED" "$LOCAL" "abcdef1" "100644" "$REMOTE" "abcdef2" "100644" -``` - -You can now use difftastic as a difftool: - -``` -$ git difftool -t difftastic -``` - -For the best results when using difftastic as a difftool, we recommend -the following additional git configuration: - -```ini -[difftool] - # Run the difftool immediately, don't ask 'are you sure' each time. - prompt = false - -[pager] - # Use a pager if the difftool output is larger than one screenful, - # consistent with the behaviour of `git diff`. - difftool = true - -[diff] - # Set difftastic as the default difftool, so we don't need to specify - # `-t difftastic` every time. - tool = difftastic -``` diff --git a/manual/src/glossary.md b/manual/src/glossary.md deleted file mode 100644 index e03cbaa4e..000000000 --- a/manual/src/glossary.md +++ /dev/null @@ -1,58 +0,0 @@ -# Glossary - -Atom -: An atom is an item in difftastic's syntax tree structure -that has no children. It represents things like literals, variable -names, and comments. See also 'list'. - -Delimiter -: A paired piece of syntax. A list has an open delimiter -and a close delimiter, such as `[` and `]`. Delimiters may not be -punctuation (e.g. `begin` and `end`) and may be empty strings (e.g. infix -syntax converted to difftastic's syntax tree). - -Hunk -: A group of lines displayed together in the diff -output. Increasing the number of context lines increases the size of -the hunk. - -LHS -: Left-hand side. Difftastic compares two items, and LHS refers -to the first item. See also 'RHS'. - -Line-oriented -: A traditional diff that compares which lines have -been added or removed, unlike difftastic. For example, GNU diff or the -diffs displayed on GitHub. - -List -: A list is an item in difftastic's syntax tree structure that -has an open delimiter, children, and a close delimiter. It represents -things like expressions and function definitions. See also 'atom'. - -Novel -: An addition or a removal. Syntax is novel if it occurs -in only one of the two items being compared. - -RHS -: Right-hand side. Difftastic compares two items, and RHS -refers to the second item. See also 'LHS'. - -Root -: A syntax tree without a parent node. Roots represent -top-level definitions in the file being diffed. - -Slider -: A diffing situation where there are multiple minimal diffs -possible, due to adjacent content. It is possible to 'slide' to -produce better results in this situation. See [the discussion in Tricky -Cases](./tricky_cases.html#sliders-flat). - -Syntax node -: An item in difftastic's syntax tree structure. Either -an atom or a list. - -Token -: A small piece of syntax tracked by difftastic (e.g. `$x`, -`function` or `]`), for highlighting and aligned display. This is -either an atom or a non-empty delimiter. diff --git a/manual/src/installation.md b/manual/src/installation.md deleted file mode 100644 index 95400d9bd..000000000 --- a/manual/src/installation.md +++ /dev/null @@ -1,89 +0,0 @@ -# Installation - -Difftastic can be installed as pre-built binaries or using various package managers. - -## Pre-Built Binaries - -Difftastic releases are published as [GitHub -releases](https://github.com/Wilfred/difftastic/releases) with -pre-built binaries for Windows, macOS and Linux. Open the [latest -release page](https://github.com/Wilfred/difftastic/releases/latest), -download the file matching your OS and CPU architecture, and extract -the `difft` executable application file. - -## Package Manager - -### macOS - -If you're a **Homebrew** user, you can install -[difftastic](https://formulae.brew.sh/formula/difftastic) with `brew`. - -``` -$ brew install difftastic -``` - -### Linux and Unix - -If you're an **Arch Linux** user, you can install -[difftastic](https://archlinux.org/packages/extra/x86_64/difftastic/) -with `pacman`. - -``` -$ sudo pacman -S difftastic -``` - -If you're a **Nix** user, you can install -[difftastic](https://github.com/NixOS/nixpkgs/blob/master/pkgs/tools/text/difftastic/default.nix) -with `nix-env`. - -``` -$ nix-env --install difftastic -``` - -If you're a **Fedora** user, you can install -[difftastic](https://packages.fedoraproject.org/pkgs/rust-difftastic/difftastic/) -with `dnf`. - -``` -$ sudo dnf install difftastic -``` - -If you're a **FreeBSD** user, you can install -[difftastic](https://www.freshports.org/textproc/difftastic/) -with `pkg`. - -``` -$ sudo pkg install difftastic -``` - -### Windows - -If you're a Windows user using **Windows Package Manager** (*WinGet*), -you can install difftastic with `winget`. - -``` -$ winget install difftastic -``` - -If you're a Windows user using **Scoop**, you can install -[difftastic](https://scoop.sh/#/apps?q=difftastic) -with `scoop`. - -``` -$ scoop install difftastic -``` - -If you're a Windows user using **Chocolatey**, you can install -[difftastic](https://community.chocolatey.org/packages/difftastic) -with `choco`. - -``` -$ choco install difftastic -``` - -## Full Package Listing - -This table lists all the platforms that have packaged difftastic. - -[![Packaging status](https://repology.org/badge/vertical-allrepos/difftastic.svg)](https://repology.org/project/difftastic/versions) - diff --git a/manual/src/introduction.md b/manual/src/introduction.md deleted file mode 100644 index 199c1fdef..000000000 --- a/manual/src/introduction.md +++ /dev/null @@ -1,66 +0,0 @@ -# Introduction - -Difftastic is a structural diff tool that understands syntax. It -supports [over 30 programming languages](./languages_supported.html) -and when it works, it's *fantastic*. - -Difftastic is open source software (MIT license) and [available on -GitHub](https://github.com/wilfred/difftastic). - -This copy of the manual describes version DFT_VERSION_HERE. The -[changelog](https://github.com/Wilfred/difftastic/blob/master/CHANGELOG.md) -records which features and bug fixes are in each version. - -*This manual is also available in [Chinese](https://difftastic.wilfred.me.uk/zh-CN/).* - -## Syntactic Diffing - -Difftastic [detects the language](./language_detection.html), parses the code, and then -compares the syntax trees. Let's look at an example. - -``` -// old.rs -let ts_lang = guess(path, guess_src).map(tsp::from_language); -``` -``` -// new.rs -let ts_lang = language_override - .or_else(|| guess(path, guess_src)) - .map(tsp::from_language); -``` - -
$ difft old.rs new.rs
-
-1 1 let ts_lang = language_override
-. 2     .or_else(|| guess(path, guess_src))
-. 3     .map(tsp::from_language);
-
-
- -Notice how difftastic recognises that `.map` is unchanged, even though -it's now on a new line with whitespace. - -A line-oriented diff does a much worse job here. - -
$ diff -u old.rs new.rs
-
-@@ -1 +1,3 @@
--let ts_lang = guess(path, guess_src).map(tsp::from_language);
-+let ts_lang = language_override
-+    .or_else(|| guess(path, guess_src))
-+    .map(tsp::from_language);
-
-
- -Some line-oriented diff tools also highlight word changes (e.g. GitHub -or git's `--word-diff`). They still don't understand the code -though. Difftastic will always find matched delimiters: you can see -the closing `)` from `or_else` has been highlighted. - -## Fallback Line-Oriented Diffing - -If input files are not in a format that difftastic understands, it -uses a conventional line-oriented diff with word highlighting. - -Difftastic will also use line-oriented diffing when given extremely -large inputs. diff --git a/manual/src/jj.md b/manual/src/jj.md deleted file mode 100644 index 43bbebf4a..000000000 --- a/manual/src/jj.md +++ /dev/null @@ -1,13 +0,0 @@ -# Jujutsu - -Jujutsu supports [external diff -commands](https://jj-vcs.github.io/jj/latest/config/#generating-diffs-by-external-command). - -To use difftastic for diffing in jujutsu, add the following to your -[user configuration -file](https://jj-vcs.github.io/jj/latest/config/#user-config-files). - -```toml -[ui] -diff-formatter = ["difft", "--color=always", "$left", "$right"] -``` diff --git a/manual/src/language_detection.md b/manual/src/language_detection.md deleted file mode 100644 index 96772f699..000000000 --- a/manual/src/language_detection.md +++ /dev/null @@ -1,30 +0,0 @@ -# Language Detection - -Difftastic guesses the language used based on the file extension, file -name, and the contents of the first few lines. - -To see the languages available, and the associated file names, use the -`--list-languages` option. - -```bash -$ difft --list-languages -... -XML - *.ant *.csproj *.plist *.resx *.svg *.ui *.vbproj *.xaml *.xml *.xsd *.xsl *.xslt *.zcml App.config nuget.config packages.config .classpath .cproject .project -YAML - *.yaml *.yml -Zig - *.zig -``` - -You can override language detection for specific file globs using the -`--override` option. - -```bash -$ difft --override=GLOB:NAME FIRST-FILE SECOND-FILE - -# For example, treating .h files as C rather than C++: -$ difft --override=*.h:c sample_files/preprocessor_1.h sample_files/preprocessor_2.h -``` - -See `difft --help` for more examples of `--override` usage. diff --git a/manual/src/languages_supported.md b/manual/src/languages_supported.md deleted file mode 100644 index 4275af4e1..000000000 --- a/manual/src/languages_supported.md +++ /dev/null @@ -1,77 +0,0 @@ -# Languages Supported - -This page lists all the languages supported by difftastic. You can -also view the languages supported in your current installed version -with `difft --list-languages`. - -## Programming Languages - -| Language | Parser Used | -|-----------------|-----------------------------------------------------------------------------------------------------------------| -| Ada | [briot/tree-sitter-ada](https://github.com/briot/tree-sitter-ada) | -| Apex | [aheber/tree-sitter-sfapex](https://github.com/aheber/tree-sitter-sfapex) | -| Assembly | [RubixDev/tree-sitter-asm](https://github.com/RubixDev/tree-sitter-asm) | -| Bash | [tree-sitter/tree-sitter-bash](https://github.com/tree-sitter/tree-sitter-bash) | -| C | [tree-sitter/tree-sitter-c](https://github.com/tree-sitter/tree-sitter-c) | -| C++ | [tree-sitter/tree-sitter-cpp](https://github.com/tree-sitter/tree-sitter-cpp) | -| C# | [tree-sitter/tree-sitter-c-sharp](https://github.com/tree-sitter/tree-sitter-c-sharp) | -| Clojure | [grammar-orchard/tree-sitter-clojure-orchard](https://codeberg.org/grammar-orchard/tree-sitter-clojure-orchard) | -| CMake | [uyha/tree-sitter-cmake](https://github.com/uyha/tree-sitter-cmake) | -| Common Lisp | [theHamsta/tree-sitter-commonlisp](https://github.com/theHamsta/tree-sitter-commonlisp) | -| Dart | [grammar-orchard/tree-sitter-dart-orchard](https://codeberg.org/grammar-orchard/tree-sitter-dart-orchard) | -| Device Tree | [joelspadin/tree-sitter-devicetree](https://github.com/joelspadin/tree-sitter-devicetree) | -| Dockerfile | [wharflab/tree-sitter-containerfile](https://github.com/wharflab/tree-sitter-containerfile) | -| Elixir | [elixir-lang/tree-sitter-elixir](https://github.com/elixir-lang/tree-sitter-elixir) | -| Elm | [elm-tooling/tree-sitter-elm](https://github.com/elm-tooling/tree-sitter-elm) | -| Erlang | [WhatsApp/tree-sitter-erlang](https://github.com/WhatsApp/tree-sitter-erlang) | -| Emacs Lisp | [wilfred/tree-sitter-elisp](https://github.com/Wilfred/tree-sitter-elisp) | -| Fish | [ram02z/tree-sitter-fish](https://github.com/ram02z/tree-sitter-fish) | -| F# | [ionide/tree-sitter-fsharp](https://github.com/ionide/tree-sitter-fsharp) | -| Fortran | [stadelmanma/tree-sitter-fortran](https://github.com/stadelmanma/tree-sitter-fortran) | -| Gleam | [gleam-lang/tree-sitter-gleam](https://github.com/gleam-lang/tree-sitter-gleam) | -| Go | [tree-sitter/tree-sitter-go](https://github.com/tree-sitter/tree-sitter-go) | -| Haskell | [tree-sitter/tree-sitter-haskell](https://github.com/tree-sitter/tree-sitter-haskell) | -| Janet | [sogaiu/tree-sitter-janet-simple](https://github.com/sogaiu/tree-sitter-janet-simple) | -| Java | [tree-sitter/tree-sitter-java](https://github.com/tree-sitter/tree-sitter-java) | -| JavaScript, JSX | [tree-sitter/tree-sitter-javascript](https://github.com/tree-sitter/tree-sitter-javascript) | -| Julia | [tree-sitter/tree-sitter-julia](https://github.com/tree-sitter/tree-sitter-julia) | -| Kotlin | [fwcd/tree-sitter-kotlin](https://github.com/fwcd/tree-sitter-kotlin) | -| Lua | [tree-sitter-grammars/tree-sitter-lua](https://github.com/tree-sitter-grammars/tree-sitter-lua) | -| Make | [tree-sitter-grammars/tree-sitter-make](https://github.com/tree-sitter-grammars/tree-sitter-make) | -| Nix | [nix-community/tree-sitter-nix](https://github.com/nix-community/tree-sitter-nix) | -| Objective-C | [amaanq/tree-sitter-objc](https://github.com/amaanq/tree-sitter-objc) | -| OCaml | [tree-sitter/tree-sitter-ocaml](https://github.com/tree-sitter/tree-sitter-ocaml) | -| Pascal | [Isopod/tree-sitter-pascal](https://github.com/Isopod/tree-sitter-pascal) | -| Perl | [tree-sitter-perl/tree-sitter-perl](https://github.com/tree-sitter-perl/tree-sitter-perl) | -| PHP | [tree-sitter/tree-sitter-php](https://github.com/tree-sitter/tree-sitter-php) | -| Python | [tree-sitter/tree-sitter-python](https://github.com/tree-sitter/tree-sitter-python) | -| QML | [yuja/tree-sitter-qmljs](https://github.com/yuja/tree-sitter-qmljs) | -| R | [r-lib/tree-sitter-r](https://github.com/r-lib/tree-sitter-r) | -| Racket | [6cdh/tree-sitter-racket](https://github.com/6cdh/tree-sitter-racket) | -| Ruby | [tree-sitter/tree-sitter-ruby](https://github.com/tree-sitter/tree-sitter-ruby) | -| Rust | [grammar-orchard/tree-sitter-rust-orchard](https://codeberg.org/grammar-orchard/tree-sitter-rust-orchard) | -| Scala | [tree-sitter/tree-sitter-scala](https://github.com/tree-sitter/tree-sitter-scala) | -| Scheme | [6cdh/tree-sitter-scheme](https://github.com/6cdh/tree-sitter-scheme) | -| Smali | [amaanq/tree-sitter-smali](https://github.com/amaanq/tree-sitter-smali) | -| Solidity | [JoranHonig/tree-sitter-solidity](https://github.com/JoranHonig/tree-sitter-solidity) | -| SQL | [derekstride/tree-sitter-sql](https://github.com/derekstride/tree-sitter-sql) | -| Swift | [alex-pinkus/tree-sitter-swift](https://github.com/alex-pinkus/tree-sitter-swift) | -| TypeScript, TSX | [tree-sitter/tree-sitter-typescript](https://github.com/tree-sitter/tree-sitter-typescript) | -| Verilog | [tree-sitter/tree-sitter-verilog](https://github.com/tree-sitter/tree-sitter-verilog) | -| VHDL | [JLeemaster/tree-sitter-vhdl](https://github.com/JLeemaster/tree-sitter-vhdl) | -| Zig | [tree-sitter-grammars/tree-sitter-zig](https://github.com/tree-sitter-grammars/tree-sitter-zig) | - -## Structured Text Formats - -| Language | Parser Used | -|----------|---------------------------------------------------------------------------------------------------| -| CSS | [tree-sitter/tree-sitter-css](https://github.com/tree-sitter/tree-sitter-css) | -| HCL | [tree-sitter-grammars/tree-sitter-hcl](https://github.com/tree-sitter-grammars/tree-sitter-hcl) | -| HTML | [tree-sitter/tree-sitter-html](https://github.com/tree-sitter/tree-sitter-html) | -| JSON | [tree-sitter/tree-sitter-json](https://github.com/tree-sitter/tree-sitter-json) | -| LaTeX | [latex-lsp/tree-sitter-latex](https://github.com/latex-lsp/tree-sitter-latex) | -| Newick | [delehef/tree-sitter-newick](https://github.com/delehef/tree-sitter-newick) | -| Proto | [coder3101/tree-sitter-proto](https://github.com/coder3101/tree-sitter-proto) | -| TOML | [tree-sitter-grammars/tree-sitter-toml](https://github.com/tree-sitter-grammars/tree-sitter-toml) | -| XML | [tree-sitter-grammars/tree-sitter-xml](https://github.com/tree-sitter-grammars/tree-sitter-xml) | -| YAML | [tree-sitter-grammars/tree-sitter-yaml](https://github.com/tree-sitter-grammars/tree-sitter-yaml) | diff --git a/manual/src/line_diffing.md b/manual/src/line_diffing.md deleted file mode 100644 index 83be380d2..000000000 --- a/manual/src/line_diffing.md +++ /dev/null @@ -1,101 +0,0 @@ -# Line Diffing - -Most diff tools today use LCS algorithms. They typically apply to -lines, but in some cases they're word-based. - -## Myers' diff algorithm - -This is the default diff algorithm in GNU diff and git diff. It finds -the longest common subsequence (LCS) and is used on a line-by-line basis. - -There's a -[great introduction -here](https://blog.jcoglan.com/2017/02/12/the-myers-diff-algorithm-part-1/) -and the original paper is [An O(ND) Difference Algorithm and Its -Variations, Myers -1986](http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.4.6927). - -``` -# Modern diff supports colour, but see also -# https://www.colordiff.org/ -$ diff --color=always -u sample_files/css_1.css sample_files/css_2.css -``` - -Note that GNU diff [originally used the Hunt-McIlroy -algorithm](http://fabiensanglard.net/git_code_review/diff.php). - -## Patience Diff - -Myers' diff has a problem with sliders: - -```diff - if (!$smtp_server) { -+ $smtp_server = $repo->config('sendemail.smtpserver'); -+} -+if (!$smtp_server) { - foreach (qw( /usr/sbin/sendmail /usr/lib/sendmail )) { - if (-x $_) { - $smtp_server = $_; -``` - -Instead of: - -```diff -+if (!$smtp_server) { -+ $smtp_server = $repo->config('sendemail.smtpserver'); -+} - if (!$smtp_server) { - foreach (qw( /usr/sbin/sendmail /usr/lib/sendmail )) { - if (-x $_) { -``` - -Git has a `--indent-heuristic` that [was added to reduce the -likelihood of making a bad -choice](https://github.com/git/git/commit/433860f3d0beb0c6f205290bd16cda413148f098). There's -a [corpus of test files](https://github.com/mhagger/diff-slider-tools) -where the ideal diff has been chosen by a human, to test different -heuristics. - -The [patience diff -algorithm](https://bramcohen.livejournal.com/73318.html) is an LCS -algorithm that aims to do a better job with sliders. It produces great -results by [doing more -work](https://stackoverflow.com/questions/40133534/is-gits-implementation-of-the-patience-diff-algorithm-correct/40159510#40159510). - -``` -# Original behaviour -$ git diff --no-indent-heuristic --no-index sample_files/css_1.css sample_files/css_2.css -# As of git 2.11, this heuristic is enabled by default. -$ git diff --indent-heuristic --no-index sample_files/css_1.css sample_files/css_2.css -# Patience algorithm does a better a job in this example. -$ git diff --patience --no-index sample_files/css_1.css sample_files/css_2.css -``` - -[Diff Match Patch](https://github.com/google/diff-match-patch) also -has some excellent discussions of diff designs on the author's website -(e.g [diff strategies](https://neil.fraser.name/writing/diff/)). - -## Histogram Diff - -Git 1.7.7+ also has a [histogram -algorithm](https://stackoverflow.com/a/32367597/509706), which aims to -produce better results than Myers' algorithm but without [the slowdown -of the patience algorithm](https://github.com/git/git/commit/85551232b56e763ecfcc7222e0858bac4e962c80). - -``` -# Inferior to patience on this example file. -$ git diff --histogram --no-index sample_files/css_1.css sample_files/css_2.css -``` - -## prettydiff - -[prettydiff](https://github.com/romankoblov/prettydiff) does really -well out of the box with the sample files here. It implements LCS on words. - -## diff-so-fancy - -[diff-so-fancy](https://github.com/so-fancy/diff-so-fancy) consumes -normal `diff` output, so it's line based. It also performs word -highlighting within lines, and generally has a prettier set of -defaults. - diff --git a/manual/src/mercurial.md b/manual/src/mercurial.md deleted file mode 100644 index 228557f13..000000000 --- a/manual/src/mercurial.md +++ /dev/null @@ -1,48 +0,0 @@ -# Mercurial - -Mercurial [supports external diff -tools](https://www.mercurial-scm.org/wiki/ExtdiffExtension) with the -Extdiff extension. Enable it by adding an entry to `extensions` in -your `.hgrc`. - -``` -[extensions] -extdiff = -``` - -You can then run `hg extdiff -p difft` instead of `hg diff` -(assumes the `difft` binary is on your `$PATH`). - -You can also define an alias to run difftastic with hg. Add the -following to your `.hgrc` to run difftastic with `hg dft`. - -``` -[extdiff] -cmd.dft = difft -# You can add further options which will be passed to the command line, e.g. -# opts.dft = --background light -``` - -All options of `hg diff` are also supported by `hg dft`; for example, -`hg dft --stat` will show statistics of changed lines and `hg dft -r 42 -r 45` -will show the diff between two revisions. - -## hg log -p - -Mercurial does not have a way of changing the default diff tool, at -least to the author's knowledge. - -If you just want to view the diff of the most recent commit, you can -use the following. - -``` -hg dft -r .^ -r . -``` - -This is equivalent to `hg log -l 1 -p`, although it does not show the -commit message. I like to define an alias for this: - -``` -[alias] -dp = dft -r .^ -r . -``` diff --git a/manual/src/packaging_difftastic.md b/manual/src/packaging_difftastic.md deleted file mode 100644 index e42404b89..000000000 --- a/manual/src/packaging_difftastic.md +++ /dev/null @@ -1,100 +0,0 @@ -# Packaging Difftastic - -This page contains recommendations for people creating a difftastic -package. - -Note that the difftastic author only provides the source code and the -prebuilt binaries on GitHub. Packages have been created by other -people -- thank you! - -## Packaging The Binary - -Difftastic can be built with `cargo`. The compiled binary will be at -`target/release/difft` when using the following command. - -``` -$ cargo build --release -``` - -C library dependencies are built with the `cc` crate, which [has -various environment -variables](https://docs.rs/cc/1.1.30/cc/index.html#external-configuration-via-environment-variables) -to configure the C toolchain (e.g. `CFLAGS`). - -### Reproducible Builds - -Difftastic's build script (the `build.rs` file) uses Rayon to build C -libraries in parallel, which can lead to minor ordering changes in the -final binary. - -You can avoid this by disabling Rayon parallelism. - -```bash -$ RAYON_NUM_THREADS=1 cargo build --release -``` - -### MIME Database - -Difftastic depends on -[tree_magic_mini](https://docs.rs/tree_magic_mini/latest/tree_magic_mini/), -which accesses the MIME database on the current system. The MIME -database is used to recognise file types, so difftastic does not try -to compare binary files as text. - -This means that the difftastic package should depend on a MIME -database package, if available. - -Difftastic respects the [XDG base -specification](https://specifications.freedesktop.org/basedir-spec/latest/index.html#basics) -to find the MIME database files. These files are typically at -`/usr/share/mime/`, `/usr/local/share/mime/` or -`/opt/homebrew/share/mime/`. - -## Man Page - -As of difftastic 0.58, a man page is available. See the file -`difft.1`. - -This file is generated from `difft.1.md`, but the generated `difft.1` -is included in the repository for convenience. - -## The Manual - -Please consider including the difftastic manual with your -package. These are HTML files that can be generated with `mdbook`. The -following command generates HTML at `manual/book/`. - -``` -$ cd manual -$ mdbook build -``` - -`manual/book.toml` also references a script -`replace_version_placeholder.sh` that replaces occurrences of -`DFT_VERSION_HERE` in the manual. For packaging, it may be easier to -remove the configuration from `book.toml` and replace the text -directly. - -```diff --[preprocessor.replace-version-placeholder] --command = "./replace_version_placeholder.sh" -``` - -``` -$ export CURRENTVERSION="7.8.9" -$ sed -i "s/DFT_VERSION_HERE/$CURRENTVERSION/g" src/introduction.md -``` - -## Testing - -If your packaging tool supports testing, consider running the -difftastic unit tests. - -``` -# Run the normal tests. -$ cargo test - -# Run the tests that depend on the -# MIME database being present. -$ cargo test -- --ignored -``` diff --git a/manual/src/parser_vendoring.md b/manual/src/parser_vendoring.md deleted file mode 100644 index a94f91085..000000000 --- a/manual/src/parser_vendoring.md +++ /dev/null @@ -1,67 +0,0 @@ -# Vendoring - -## Git Subtrees - -Tree-sitter parsers are sometimes not packaged on crates.io. In that case, Difftastic uses -git subtrees (not git submodules) to track them. - -## Vendoring a parser - -Once you've found the source repository for the parser, add it as a git subtree to -`vendored_parsers/`. We'll use -[tree-sitter-json](https://github.com/tree-sitter/tree-sitter-json) as -an example. - -``` -$ git subtree add --prefix=vendored_parsers/tree-sitter-json https://github.com/tree-sitter/tree-sitter-json.git master -``` - -### Configure the build - -Cargo does not allow packages to include subdirectories that contain a -`Cargo.toml`. Add a symlink to the `src/` parser subdirectory. - -``` -$ cd vendored_parsers -$ ln -s tree-sitter-json/src tree-sitter-json-src -``` - -You can now add the parser to build by including the directory in -`build.rs`. - -``` -TreeSitterParser { - name: "tree-sitter-json", - src_dir: "vendored_parsers/tree-sitter-json-src", - extra_files: vec![], -}, -``` - -If your parser includes custom C or C++ files for lexing (e.g. a -`scanner.cc`), add them to `extra_files`. - -## Syntax highlighting (Optional) - -To add syntax highlighting for your language, you'll also need a symlink -to the `queries/highlights.scm` file, if available. - -``` -$ cd vendored_parsers/highlights -$ ln -s ../tree-sitter-json/queries/highlights.scm json.scm -``` - -## Updating a parser - -To update a parser, pull commits from the upstream git repository. For -example, the following command will update the Java parser: - -``` -$ git subtree pull --prefix=vendored_parsers/tree-sitter-java git@github.com:tree-sitter/tree-sitter-java.git master -``` - -To see when each parser was last updated, use the following shell -command: - -``` -$ for d in $(git log vendored_parsers/* | grep git-subtree-dir | tr -d ' ' | cut -d ":" -f2 | sort); do echo "$d"; git log --pretty=" %cs" -n 1 $d; done -``` diff --git a/manual/src/parsing.md b/manual/src/parsing.md deleted file mode 100644 index 1d19b3bcd..000000000 --- a/manual/src/parsing.md +++ /dev/null @@ -1,97 +0,0 @@ -# Internals: Parsing - -Difftastic uses -[tree-sitter](https://tree-sitter.github.io/tree-sitter/) to build a -parse tree. The parse tree is then converted to a simpler tree which -can be diffed. - -## Parsing with Tree-sitter - -Difftastic relies on tree-sitter to understand syntax. You can view -the parse tree that tree-sitter produces using the `--dump-ts` -flag. - -``` -$ difft --dump-ts sample_files/javascript_simple_1.js | head -program (0, 0) - (7, 0) - comment (0, 0) - (0, 8) "// hello" - expression_statement (1, 0) - (1, 6) - call_expression (1, 0) - (1, 5) - identifier (1, 0) - (1, 3) "foo" - arguments (1, 3) - (1, 5) - ( (1, 3) - (1, 4) "(" - ) (1, 4) - (1, 5) ")" - ; (1, 5) - (1, 6) ";" - expression_statement (2, 0) - (2, 6) -``` - -## Simplified Syntax - -Difftastic converts the tree-sitter parse tree to a simplified syntax -tree. The syntax tree is a uniform representation where everything is -either an atom (e.g. integer literals, comments, variable names) or a -list (consisting of the open delimiter, children and the close -delimiter). - -The flag `--dump-syntax` will display the syntax tree generated for a -file. - -``` -$ difft --dump-syntax sample_files/before.js -[ - Atom id:1 { - content: "// hello", - position: "0:0-8", - }, - List id:2 { - open_content: "", - open_position: "1:0-0", - children: [ - ... -``` - -### Conversion Process - -The simple representation of the difftastic parse tree makes diffing -much easier. Converting the detailed tree-sitter parse tree is a -recursive tree walk, treating tree-sitter leaf nodes as atoms. There -are two exceptions. - -(1) Tree-sitter parse trees sometimes include unwanted structure. Some -grammars consider string literals to be a single token, whereas others -treat strings as a complex structure where the delimiters are -separate. - -`tree_sitter_parser.rs` uses `atom_nodes` to mark specific tree-sitter -node names as flat atoms even if the node has children. - -(2) Tree-sitter parse trees include open and closing delimiters as -tokens. A list `[1]` will have a parse tree that includes `[` and `]` -as nodes. - -``` -$ echo '[1]' > example.js -$ difft --dump-ts example.js -program (0, 0) - (1, 0) - expression_statement (0, 0) - (0, 3) - array (0, 0) - (0, 3) - [ (0, 0) - (0, 1) "[" - number (0, 1) - (0, 2) "1" - ] (0, 2) - (0, 3) "]" -``` - -`tree_sitter_parser.rs` uses `open_delimiter_tokens` to ensure that -`[` and `]` are used as delimiter content in the enclosing list, -rather than converting them to atoms. - -Difftastic can match up atoms that occur in different parts of the -simplified syntax tree. If e.g. a `[` is treated as an atom, -difftastic might match it with another `[` elsewhere. The resulting -diff would be unbalanced, highlighting different numbers of open and -close delimiters. - -### Lossy Syntax Trees - -The simplified syntax tree only stores node content and node -position. It does not store whitespace between nodes, and position is -ignored during diffing. diff --git a/manual/src/profiling.md b/manual/src/profiling.md deleted file mode 100644 index 47f9056ab..000000000 --- a/manual/src/profiling.md +++ /dev/null @@ -1,27 +0,0 @@ -## Profiling - -If you have a file that's particularly slow, you can use -[cargo-flamegraph](https://github.com/flamegraph-rs/flamegraph) to see -which functions are slow. - -``` -$ CARGO_PROFILE_RELEASE_DEBUG=true cargo flamegraph --bin difft -- sample_files/slow_1.rs sample_files/slow_2.rs -``` - -It's also worth looking at memory usage, as graph traversal bugs can -lead to huge memory consumption. - -``` -$ /usr/bin/time -v ./target/release/difft sample_files/slow_1.rs sample_files/slow_2.rs -``` - -If timing measurements are noisy, Linux's `perf` tool will report -instructions executed, which is more stable. - -``` -$ perf stat ./target/release/difft sample_files/slow_1.rs sample_files/slow_2.rs -$ perf stat ./target/release/difft sample_files/typing_1.ml sample_files/typing_2.ml -``` - -Many more profiling techniques are discussed in [The Rust Performance -Book](https://nnethercote.github.io/perf-book/). diff --git a/manual/src/robots.txt b/manual/src/robots.txt deleted file mode 100644 index c2a49f4fb..000000000 --- a/manual/src/robots.txt +++ /dev/null @@ -1,2 +0,0 @@ -User-agent: * -Allow: / diff --git a/manual/src/tree_diffing.md b/manual/src/tree_diffing.md deleted file mode 100644 index 77fb329fd..000000000 --- a/manual/src/tree_diffing.md +++ /dev/null @@ -1,118 +0,0 @@ -# Tree Diffing - -This page summarises some of the other tree diffing tools available. - -If you're in a hurry, start by looking at Autochrome. It's extremely -capable, and has an excellent description of the design. - -If you're interested in a summary of the academic literature, [this -blog -post](http://useless-factor.blogspot.com/2008/01/matching-diffing-and-merging-xml.html) -(and its [accompanying -paper](https://github.com/Wilfred/difftastic/files/7826933/14482474-XML-diff-survey.pdf) --- mirrored under a CC BY-NC license) are great resources. - -## json-diff (2012) - -Languages: JSON -Algorithm: Pairwise comparison -Output: CLI colours - -[json-diff](https://github.com/andreyvit/json-diff) performs a -structural diff of JSON files. It considers subtrees to be different -if they don't match exactly, so e.g. `"foo"` and `["foo"]` are -entirely different. - -json-diff is also noteworthy for its extremely readable display of -results. - -## GumTree (2014) - -Languages: [~10 programming -languages](https://github.com/GumTreeDiff/gumtree/wiki/Languages) -Parser: Several, including [srcML](https://www.srcml.org/) -Algorithm: Top-down, then bottom-up -Output: HTML, Swing GUI, or text - -[GumTree](https://github.com/GumTreeDiff/gumtree) can parse several -programming languages and then performs a tree-based diff, outputting -an HTML display. - -The GumTree algorithm is described in the associated paper -'Fine-grained and accurate source code differencing' by Falleri et al -([DOI](http://doi.acm.org/10.1145/2642937.2642982), -[PDF](https://hal.archives-ouvertes.fr/hal-01054552/document)). It -performs a greedy top-down search for identical subtrees, then -performs a bottom-up search to match up the rest. - -## Tree Diff (2017) - -Languages: S-expression data format -Algorithm: A* search -Output: Merged s-expression file - -Tristan Hume wrote a tree diffing algorithm during his 2017 internship -at Jane Street. The source code is not available, but [he has a blog -post](https://thume.ca/2017/06/17/tree-diffing/) discussing the design -in depth. - -This project finds minimal diffs between s-expression files used as -configuration by Jane Street. It uses A* search to find the minimal -diff between them, and builds a new s-expression with a section marked -with `:date-switch` for the differing parts. - -(Jane Street also has patdiff, but that seems to be a line-oriented -diff with some whitespace/integer display polish. It doesn't -understand that e.g. whitespace in `"foo "` is meaningful). - -## Autochrome (2017) - -Languages: Clojure -Parser: Custom, preserves comments -Algorithm: Dijkstra (previously A* search) -Output: HTML - -[Autochrome](https://fazzone.github.io/autochrome.html) parses Clojure -with a custom parser that preserves comments. Autochrome uses -Dijkstra's algorithm to compare syntax trees. - -Autochrome's webpage includes worked examples of the algorithm and a -discussion of design tradeoffs. It's a really great resource for -understanding tree diffing techniques in general. - -## graphtage (2020) - -Languages: JSON, XML, HTML, YAML, plist, and CSS -Parser: json5, pyYAML, ignores comments -Algorithm: Levenshtein distance -Output: CLI colours - -[graphtage](https://blog.trailofbits.com/2020/08/28/graphtage/) -compares structured data by parsing into a generic file format, then -displaying a diff. It even allows things like diffing JSON against -YAML. - -As with json-diff, it does not consider `["foo"]` and `"foo"` to have -any similarities. - -## Diffsitter (2020) - -Parser: [Tree-sitter](https://tree-sitter.github.io/tree-sitter/) -Algorithm: Longest-common-subsequence -Output: CLI colours - -[Diffsitter](https://github.com/afnanenayet/diffsitter) is another -tree-sitter based diff tool. It uses [LCS diffing on the leaves of the -syntax -tree](https://github.com/afnanenayet/diffsitter/blob/b0fd72612c6fcfdb8c061d3afa3bea2b0b754f33/src/ast.rs#L310-L313). - -## sdiff (2021) - -Languages: Scheme -Parser: Scheme's built-in `read`, ignores comments -Algorithm: MH-Diff from the Chawathe paper -Output: CLI colours - -[Semantically meaningful S-expression diff: Tree-diff for lisp source -code](https://archive.fosdem.org/2021/schedule/event/sexpressiondiff/) -was presented at FOSDEM 2021. diff --git a/manual/src/tricky_cases.md b/manual/src/tricky_cases.md deleted file mode 100644 index bc014b26e..000000000 --- a/manual/src/tricky_cases.md +++ /dev/null @@ -1,512 +0,0 @@ -# Tricky Cases - -Tree diffing is challenging in some situations. This page discusses -difficult cases, and how difftastic handles them. - -Not all of these cases work well in difftastic yet. - -## Adding Delimiters - -``` -;; Before -x - -;; After -(x) -``` - -Possible result: (x) - -Desired result: (x) - -This is tricky because `x` has changed its depth in the tree, but `x` -itself is unchanged. - -Not all tree diff algorithms handle this case. It is also challenging -to display this case clearly: we want to highlight the changed -delimiters, but not their content. This is challenging in larger -expressions. - -**Difftastic**: Difftastic considers nodes to be equal even at -different depths, achieving the desired result in this case. - -## Changing Delimiters - -``` -;; Before -(x) - -;; After -[x] -``` - -Desired result: (x), [x] - -As with the wrapping case, we want to highlight the delimiters rather -than the `x`. - -**Difftastic**: Difftastic handles this correctly through its tree diffing. - -## Expanding Delimiters - -``` -;; Before -(x) y - -;; After -(x y) -``` - -Possible result 1: (x) y, (x y) - -Possible result 2: (x) y, (x y) - -It's not clear which is better in this case. - -**Difftastic**: Difftastic currently shows result 2, but this case is -sensitive to the cost model. Some previous versions of difftastic have -shown result 1. - -## Contracting Delimiters - -``` -;; Before -(x y) - -;; After -(x) y -``` - -This case is similar to the expanding delimiter case. - -## Disconnected Delimiters - -``` -;; Before -(foo (bar)) - -;; After -(foo (novel) (bar)) -``` - -Desired result: (foo (novel) (bar)) - -It is easy to end up with -(foo (novel) (bar)), -where a later pair of delimiters are chosen. - -## Rewrapping Large Nodes - -``` -;; Before -[[foo]] -(x y) - -;; After -([[foo]] x y) -``` - -We want to highlight `[[foo]]` being moved inside the -parentheses. However, a naive syntax differ prefers to consider a removal -of `()` in the before and an addition of `()` in the after to be more -minimal diff. - -(Reported as [issue 44](https://github.com/Wilfred/difftastic/issues/44).) - -## Reordering Within A List - -``` -;; Before -(x y) - -;; After -(y x) -``` - -Desired result: (y x) - -We want to highlight the list contents and not the delimiters. - -## Middle Insertions - -``` -// Before -foo(bar(123)) - -// After -foo(extra(bar(123))) -``` - -Desired result: foo(extra(bar(123))) - -We want to consider both `foo` and `bar` to be unchanged. This case is -challenging for diffing algorithms that do a bottom-up then top-down -matching of trees. - -## Punctuation Atoms - -``` -// Before -foo(1, bar) - -// After -foo(bar, 2) -``` - -Possible result: foo(bar, 2) - -Desired result: foo(bar, 2) - -There are two atoms inside the `()` that we could consider as -unchanged, either the `bar` or the `,`. (We can't consider both to be -unchanged as they're reordered.) - -We want to consider `bar` to be unchanged, as it's a more important -atom than the `,` punctuation atom. Doing this in a -language-agnostic way is difficult, so difftastic has a small list of -punctuation characters that always get lower priority than other -atoms. - -## Trailing Punctuation - -In some cases, reformatting code can change the trailing punctuation -without changing the meaning of the code. We don't want to show a diff -in this case. - -``` -# Before -foo(x, y) - -# After (semantically identical) -foo( - x, - y, -) -``` - -This is language-specific. For example, a trailing comma can change the meaning -of code in Python. - -``` -# Before (the value 1) -(1) - -# After (a tuple) -(1,) -``` - -Desired result: (1,) - -However, we can't simply discard this punctuation before diffing. - -``` -# Before -[2,] - -# After -[2,3,] -``` - -Possible result: [2,3,] - -Desired result: [2,3,] - -If the diffing logic effectively sees `[2]` and `[2,3]` because we've -discarded the punctuation, we don't get the desired result here. - -**Difftastic**: Difftastic solves this problem by considering lists -syntactically equal in this case. Each language configuration has a -set of AST node types (e.g. list literals) where trailing punctuation -doesn't matter. - -## Sliders (Flat) - -Sliders are a common problem in text based diffs, where lines are -matched in a confusing way. - -They typically look like this. The diff has to arbitrarily choose a -line containing a delimiter, and it chooses the wrong one. - -``` -+ } -+ -+ function foo () { - } -``` - -git-diff has some heuristics to reduce the risk of this (e.g. the -"patience diff"), but it can still occur. - -There's a similar problem in tree diffs. - -``` -;; Before -A B -C D - -;; After -A B -A B -C D -``` - -Possible result: - -
A B
-A B
-C D
-
- -Preferred result: - -
A B
-A B
-C D
-
- -Ideally we'd prefer marking contiguous nodes as novel. From the -perspective of a longest-common-subsequence algorithm, these two -choices are equivalent. - -## Sliders (Nested) - -``` -// Before -old1(old2) - -// After -old1(new1(old2)) -``` - -Possible result: old1(new1(old2)) - -Desired result: old1(new1(old2)) - -The correct answer depends on the language. Most languages want to -prefer the inner delimiter, whereas Lisps and JSON prefer the outer -delimiter. - -## Minimising Depth Changes - -``` -// Before -if true { - foo(123); -} -foo(456); - -// After -foo(789); -``` - -Do we consider `foo(123)` or `foo(456)` to match with `foo(789)`? -Difftastic prefers `foo(456)` by preferring nodes at the same nesting depth. - -## Replacements With Minor Similarities - -``` -// Before -function foo(x) { return x + 1; } - -// After -function bar(y) { baz(y); } -``` - -Possible result: function bar(y) { baz(y); } - -In this example, we've deleted a function and written a completely -different one. A tree-based diff could match up the `function` and the -outer delimiters, resulting in a confusing display showing lots of -small changes. - -As with sliders, the replacement problem can also occur in textual -line-based diffs. Line-diffs struggle if there are a small number of -common lines. The more precise, granular behaviour of tree diffs makes -this problem much more common though. - -## Matching Substrings In Comments - -``` -// Before -/* The quick brown fox. */ -foobar(); - -// After -/* The slow brown fox. */ -foobaz(); -``` - -`foobar` and `foobaz` are completely different, and their common -prefix `fooba` should not be matched up. However, matching common -prefixes or suffixes for comments is desirable. - -## Multiline Comments - -``` -// Before -/* Hello - * World. */ - -// After -if (x) { - /* Hello - * World. */ -} -``` - -The inner content of these two comments is technically different. We -want to treat them as identical however. - -## Reflowing Doc Comments - -Block comments have prefixes that aren't meaningful. - -``` -// Before -/* The quick brown fox jumps - * over the lazy dog. */ - -// After -/* The quick brown fox immediately - * jumps over the lazy dog. */ -``` - -The inner content has changed from `jumps * over` to `immediately * -jumps over`. However, the `*` is decorative and we don't care that -it's moved. - -## Small Changes To Large Strings - -``` -// Before -"""A very long string -with lots of words about -lots of stuff.""" - -// After -"""A very long string -with lots of NOVEL words about -lots of stuff.""" -``` - -It would be correct to highlight the entire string literal as being -removed and replaced with a new string literal. However, this makes it -hard to see what's actually changed. - -It's clear that variable names should be treated atomically, and -comments are safe to show subword changes. It's not clear how to -handle a small change in a 20 line string literal. - -It's tempting to split strings on spaces and diff that, but users -still want to know when whitespace changes inside strings. `" "` and -`" "` are not the same. - -## Unordered Data Types - -``` -// Before -set(1, 2) - -// After -set(2, 1) -``` - -Users may expect difftastic to find no changes here. This is difficult -for several reasons. - -For programming languages, side effects might make the order -relevant. `set(foo(), bar())` might behave differently to `set(bar(), -foo())`. - -For configuration languages like JSON or YAML, some parser -implementations do actually expose ordering information -(e.g. `object_pairs_hook=OrderedDict` in Python, or serde_json's -`preserve_order` feature in Rust). - -To make matters worse, unordered tree diffing is NP-hard. - -> For the unordered case, it turns out that all of the problems in -> general are NP-hard. Indeed, the tree edit distance and alignment -> distance problems are even MAX SNP-hard. -> -> -- [A survey on tree edit distance and related problems](https://doi.org/10.1016/j.tcs.2004.12.030) - -**Difftastic**: Difftastic considers ordering to be meaningful -everywhere, so it will always report ordering changes. - -## Novel Blank Lines - -Blank lines are challenging for syntactic diffs. We are comparing -syntactic tokens, so we don't see blank lines. - -``` -// Before -A -B - -// After -A - -B -``` - -Generally we want syntactic diffing to ignore blank lines. In this -first example, this should show no changes. - -This is occasionally problematic, as it can hide accidental code -reformatting. - -``` -// Before -A -B - -// After -A -X - -Y -B -``` - -In this second example, we've inserted X and Y and a blank line. We -want to highlight the blank line as an addition. - -``` -// Before -A - - -B - -// After -A -X -B -``` - -In this third example, the syntactic diffing only sees an -addition. From the user's perspective, there has also been a removal -of two blank lines. - -## Invalid Syntax - -There's no guarantee that the input we're given is valid syntax. Even -if the code is valid, it might use syntax that isn't supported by the -parser. - -**Difftastic**: Difftastic will fall back to a line-oriented diff if -any parse errors occur, to avoid diffing incomplete syntax trees. When -this occurs, the file header reports the error count along with the -position of the first parse error. - -``` -$ difft sample_files/syntax_error_1.js sample_files/syntax_error_2.js -sample_files/syntax_error_2.js --- Text (2 JavaScript parse errors, exceeded DFT_PARSE_ERROR_LIMIT, first at 3:1) -... -``` - -Users may opt-in to syntactic diffing by setting -`DFT_PARSE_ERROR_LIMIT` to a larger value. In this mode, difftastic -treats tree-sitter error nodes as atoms and performs a tree diff as -normal. diff --git a/manual/src/usage.md b/manual/src/usage.md deleted file mode 100644 index fb30ba9a6..000000000 --- a/manual/src/usage.md +++ /dev/null @@ -1,94 +0,0 @@ -# Usage - -This page describes how to use the `difft` binary directly. See also -the [Git](./git.html), [Mercurial](./mercurial.html), -[Fossil](./fossil.html), or [Jujutsu](./jj.html) pages for instructions on how to configure -them to use difftastic. - -## File Arguments - -### Diffing Files - -```bash -$ difft FIRST-FILE SECOND-FILE - -# For example: -$ difft sample_files/simple_1.js sample_files/simple_2.js -``` - -### Diffing Directories - -```bash -$ difft FIRST-DIRECTORY SECOND-DIRECTORY - -# For example: -$ difft sample_files/dir_1/ sample_files/dir_2/ -``` - -Difftastic will recursively walk the two directories, diffing files -with the same name. - -The `--skip-unchanged` option is useful when diffing directories that -contain many unchanged files. - -### Reading stdin - -You can read a file from stdin by specifying `-` as the file path. - -```bash -$ difft - SECOND-FILE - -# For example: -$ cat sample_files/simple_1.js | difft - sample_files/simple_2.js -``` - -### Files With Conflicts - -*(Added in version 0.50.)* - -If you have a file with `<<<<<<<` conflict markers, you can pass it as -a single argument to difftastic. Difftastic will construct the two -file states and diff those. - -```bash -$ difft FILE-WITH-CONFLICTS - -# For example: -$ difft sample_files/conflicts.el -``` - -## Configuration Options - -Every difftastic option can be set with a command line argument or an -environment variable. For example, `DFT_BACKGROUND=light` is equivalent to -`--background=light`. - -Environment variables are often useful when using VCS tools like git, -because they invoke the `difft` binary directly. - -For a full list of configuration options, see `--help`. - -``` -$ difft --help -... -OPTIONS: - --background - Set the background brightness. Difftastic will prefer brighter colours on dark backgrounds. - - [env: DFT_BACKGROUND=] - [default: dark] - [possible values: dark, light] -... -``` - -## Exit Codes - -2: Difftastic was given invalid arguments. This includes invalid usage -(e.g. the wrong number of arguments) as well as paths that difftastic -cannot read (e.g. non-existent paths or insufficient permissions). - -1: When called with `--exit-code`, difftastic will return an exit code -of 1 when it finds any syntactic changes (in text files) or byte changes -(in binary files). - -0: All other cases. diff --git a/manual/theme/favicon.svg b/manual/theme/favicon.svg deleted file mode 100644 index 0a4f5a66c..000000000 --- a/manual/theme/favicon.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/src/options.rs b/src/options.rs index 2186a78c8..e960c3d4e 100644 --- a/src/options.rs +++ b/src/options.rs @@ -5,7 +5,7 @@ use std::ffi::OsStr; use std::fmt::Display; use std::path::{Path, PathBuf}; -use clap::{crate_authors, crate_description, Arg, ArgAction, Command}; +use clap::{crate_description, Arg, ArgAction, Command}; use crate::exit_codes::EXIT_BAD_ARGUMENTS; use crate::parse::guess_language::{language_override_from_name, LanguageOverride}; @@ -45,7 +45,7 @@ impl Default for DiffOptions { } fn app() -> clap::Command { - Command::new("Difftastic") + Command::new("diffr") // Show options in alphabetical order, rather than in // declaration order. .next_display_order(None) @@ -53,14 +53,13 @@ fn app() -> clap::Command { .version(env!("CARGO_PKG_VERSION")) .long_version(VERSION.as_str()) .about(crate_description!()) - .author(crate_authors!()) .arg( Arg::new("dump-syntax") .long("dump-syntax") .value_name("PATH") .action(ArgAction::Set) .long_help( - "Parse a single file with tree-sitter and display the difftastic syntax tree.", + "Parse a single file with tree-sitter and display the diffr syntax tree.", ).help_heading("DEBUG OPTIONS"), ) .arg( @@ -69,7 +68,7 @@ fn app() -> clap::Command { .value_name("PATH") .action(ArgAction::Set) .long_help( - "Parse a single file with tree-sitter and display the difftastic syntax tree, as a DOT graph.", + "Parse a single file with tree-sitter and display the diffr syntax tree, as a DOT graph.", ).help_heading("DEBUG OPTIONS"), ) .arg( @@ -101,7 +100,7 @@ This argument may be given more than once. For example: $ ", env!("CARGO_BIN_NAME"), " debug --override='CustomFile:json' --override='*.c:text' --dump-syntax file.c -To configure multiple overrides using environment variables, difftastic also accepts DFT_OVERRIDE_1 up to DFT_OVERRIDE_9. +To configure multiple overrides using environment variables, diffr also accepts DFT_OVERRIDE_1 up to DFT_OVERRIDE_9. $ export DFT_OVERRIDE='CustomFile:json' $ export DFT_OVERRIDE_1='*.c:text' @@ -113,7 +112,7 @@ When multiple overrides are specified, the first matching override wins.")) .arg( Arg::new("list-languages").long("list-languages") .action(ArgAction::SetTrue) - .help("Print all the languages supported by difftastic, along with their recognised extensions.") + .help("Print all the languages supported by diffr, along with their recognised extensions.") ) .arg_required_else_help(true) } diff --git a/src/tags/mod.rs b/src/tags/mod.rs index 6b012a72b..2c423bb71 100644 --- a/src/tags/mod.rs +++ b/src/tags/mod.rs @@ -272,7 +272,7 @@ mod tests { "sub/readme.txt", "CHANGELOG.md", "LICENSE", - "examples/review/viewer/README.md", + "examples/review/README.md", "CITATION.cff", ] { assert!(tags(path).contains(&DOCS), "{path}"); diff --git a/translation/zh-CN/README-zh-CN.md b/translation/zh-CN/README-zh-CN.md deleted file mode 100644 index 2443dd708..000000000 --- a/translation/zh-CN/README-zh-CN.md +++ /dev/null @@ -1,80 +0,0 @@ -

- it's difftastic! -
- manual - crates.io - codecov.io -

- -Difftastic 是一个根据文件语法进行比较的结构化比较工具。 - -**有关安装说明,详见 [说明书](http://difftastic.wilfred.me.uk/) 中的 -[安装部分](https://difftastic.wilfred.me.uk/installation.html)。** - -## 基础实例 - -![使用 Difftastic 比较 Javascript 文件的截图](/img/js.png) - -在这个 JavaScript 的例子中,我们可以看到: - -(1) Difftastic 理解嵌套。它强调了匹配的 `{` 和 -`}` 符号;同时尽管 `foo()` 之前增加了空格,Difftastic 知道它并没有改变。 - -(2) Difftastic 理解哪些行应该被对齐。尽管内容改变了,但是 Difftastic 依旧将左边的 `bar(1)` 与右边的 `bar(2)` 对齐。 - -(3) Difftastic 理解换行并不改变文件意义。例如 `"eric"` 现在在新的一行中,但 Difftastic 知道它并没改变。 - -## 一分钟演示 - -[![asciicast](https://asciinema.org/a/480875.svg)](https://asciinema.org/a/480875) - -这个一分钟录屏演示了对单个文件与 git 使用 Difftastic 的操作与效果。 - -## 语言 - -Difftastic 支持超过 30 种编程语言,完整列表请查看 [说明书](https://difftastic.wilfred.me.uk/)。 - -如果一个文件的拓展名无法被识别,Difftastic 将会使用基于文本但带高亮显示的差异分析模式。 - -## 已知问题 - -性能:Difftastic 对有大量改动的文件的拓展性较差,并且会消耗大量的内存。 - -显示:Difftastic 的并排显示功能效果通常情况下很好,但有时也会令人困惑。 - -鲁棒性:Difftastic 经常发布修复崩溃的版本。 - -## 非目标 - -修补:Difftastic 的输出是供人使用的,它不会生成可以在以后应用的补丁。如果你需要一个补丁,请使用 `diff`。 - -(补丁文件也将行作为单位的,这方面的能力对 Difftastic 十分有限。Difftastic 可以发现同一行中同时存在添加与删除,并且它会跟踪新旧文件间行号的关系。) - -合并:抽象语法树(AST)合并是一个困难的问题。Difftastic 并没有解决这个问题。 - -## 常见问题 - -### 这基本上不就是 `--word-diff --ignore-all-space` 吗? - -字符差异分析 [并不能做到这个](https://twitter.com/_wilfredh/status/1510139929971421191/photo/1)。 - -Difftastic 会解析你的代码,会去理解什么是空格、什么具有意义。例如在字符串里或是在像 Python 这样的语言中,空格就是具有意义的。同时它会理解 `x-1` 在 Javascript 中代表三个符号,而在 Lisp 中却是一个符号。 - -### 我能在 git 上使用 Difftastic 吗? - -可以!Difftastic 说明书 [包含 git 的使用说明方法](https://difftastic.wilfred.me.uk/git.html)。你也可以 [使用 mercurial](https://difftastic.wilfred.me.uk/mercurial.html)。 - -如果你使用 magit,请查看 [这篇博客](https://tsdh.org/posts/2022-08-01-difftastic-diffing-with-magit.html),它展示了使用 Difftastic 和 magit 的一种方法。 - -### Difftastic 能否与我最喜欢的工具整合? - -可能不会,但 Difftastic 还很年轻,会去考虑为你最喜欢的工具写一个插件,写好我会在 README 中链接它! - -## 许可证 - -Difftastic 是一个基于 MIT 许可证的开源软件,更多信息详见 LICENSE。 - -这个存储库的 `vendored_parsers/` 目录下还包括在 -其他作者的树状分析器。这些都基于 MIT 许可证和 Apache 许可证开源。更多细节见 `vendored_parsers/*/LICENSE`。 - -除在文件头特殊说明外,`sample_files/` 中的文件也采用 MIT 许可证。 diff --git a/translation/zh-CN/manual-zh-CN/.gitignore b/translation/zh-CN/manual-zh-CN/.gitignore deleted file mode 100644 index 7585238ef..000000000 --- a/translation/zh-CN/manual-zh-CN/.gitignore +++ /dev/null @@ -1 +0,0 @@ -book diff --git a/translation/zh-CN/manual-zh-CN/book.toml b/translation/zh-CN/manual-zh-CN/book.toml deleted file mode 100644 index 5ad05d8d7..000000000 --- a/translation/zh-CN/manual-zh-CN/book.toml +++ /dev/null @@ -1,15 +0,0 @@ -[book] -authors = ["Wilfred Hughes"] -language = "zh-CN" -src = "src" -title = "Difftastic Manual" -description = "The manual for difftastic, the structural diff tool" - -[output.html] -git-repository-url = "https://github.com/wilfred/difftastic" - -[output.html.playground] -copyable = false - -[preprocessor.replace-version-placeholder] -command = "./replace_version_placeholder.sh" diff --git a/translation/zh-CN/manual-zh-CN/replace_version_placeholder.sh b/translation/zh-CN/manual-zh-CN/replace_version_placeholder.sh deleted file mode 120000 index 778597ebd..000000000 --- a/translation/zh-CN/manual-zh-CN/replace_version_placeholder.sh +++ /dev/null @@ -1 +0,0 @@ -../../../manual/replace_version_placeholder.sh \ No newline at end of file diff --git a/translation/zh-CN/manual-zh-CN/src/SUMMARY.md b/translation/zh-CN/manual-zh-CN/src/SUMMARY.md deleted file mode 100644 index 6a242cc9f..000000000 --- a/translation/zh-CN/manual-zh-CN/src/SUMMARY.md +++ /dev/null @@ -1,18 +0,0 @@ -# 总结 - -- [简介](./introduction.md) -- [安装](./installation.md) -- [使用](./usage.md) - - [Git](./git.md) - - [Mercurial](./mercurial.md) - - [Fossil](./fossil.md) -- [支持的语言](./languages_supported.md) -- [解析](./parsing.md) -- [差异分析](./diffing.md) - - [棘手的例子](./tricky_cases.md) -- [贡献](./contributing.md) - - [解析器依赖库](./parser_vendoring.md) - - [添加解析器](./adding_a_parser.md) -- [词典](./glossary.md) -- [其它项目](./alternative_projects.md) - - [树状差异分析](./tree_diffing.md) diff --git a/translation/zh-CN/manual-zh-CN/src/adding_a_parser.md b/translation/zh-CN/manual-zh-CN/src/adding_a_parser.md deleted file mode 100644 index 941d8e756..000000000 --- a/translation/zh-CN/manual-zh-CN/src/adding_a_parser.md +++ /dev/null @@ -1,111 +0,0 @@ -# 添加解析器 - -## 寻找解析器 - -Difftastic的新解析器必须完整且合理地维护。 - -有许多解析器可用,网站包括[一些著名的解析器列表](https://tree-sitter.github.io/tree-sitter/#available-parsers)。 - -## 添加源码 - -一旦你找到一个解析器,需要将其作为git的subtree添加到`vendored_parsers/`中。我们会使用[tree-sitter-json](https://github.com/tree-sitter/tree-sitter-json)作为例子。 - -``` -$ git subtree add --prefix=vendored_parsers/tree-sitter-json git@github.com:tree-sitter/tree-sitter-json.git master -``` - -## 配置编译过程 - -Cargo不允许软件包包含`Cargo.toml`。需要在`src/`解析器子目录中添加一个符号链接。 - -``` -$ cd vendor -$ ln -s tree-sitter-json/src tree-sitter-json-src -``` - -现在你可以通过在`build.rs`中加入目录,并将解析器添加到构建中。 - -``` -TreeSitterParser { - name: "tree-sitter-json", - src_dir: "vendored_parsers/tree-sitter-json-src", - extra_files: vec![], -}, -``` - -如果你的解析器包括用于语法的自定义C或C++文件(例如,一个`scanner.cc`),请将它添加到`extra_files`中。 - -## 配置解析器 - -为你的语言在`tree_sitter_parser.rs`中增加一个条目。 - -``` -Json => { - let language = unsafe { tree_sitter_json() }; - TreeSitterConfig { - name: "JSON", - language, - atom_nodes: vec!["string"].into_iter().collect(), - delimiter_tokens: vec![("{", "}"), ("[", "]")], - highlight_query: ts::Query::new( - language, - include_str!("../vendored_parsers/highlights/json.scm"), - ) - .unwrap(), - } -} -``` - -`name`是用户节目中显示的可读名称。 - -`atom_nodes`是一个树形节点名称的列表,这些节点应被视为原子。即使这些节点有子节点,也应被视为原子。这对于字符串表面之或插值字符串非常常见的,因为在这种情况下,节点可能有用来表示开头和结尾的引用号。 - -如果你没有设置`atom_nodes`,你可能会主要添加/删除的内容显示为白色。这通常表面了子节点的父节点应该被当作原子。 - -`delimiter_tokens`是Difftastic存储在闭包节点上的定界符。这使得Difftastic能够区分划线符号和语言中的其它标点符号。 - -如果你不设置`delimiter_tokens`,Difftastic会单独考虑这些标记,并会认为是添加了`(`,但是`)`没有发生变化。 - -你可以使用`difft --dump-ts foo.json`来查看树状解析器的结果,并使用`difft --dump-syntax foo.json`来确认你已经正确设置了原子和定界符。 - -## 配置滑块 - -请为你的语言在`sliders.rs`中添加入口。 - -## 配置语言检测 - -更新`guess_language.rs`中的`from_extension`以检测新的语言。 - -``` -"json" => Some(Json), -``` - -也可能有与你的语言相关的文件名或shebangs。[GitHub的语言定义](https://github.com/github/linguist/blob/master/lib/linguist/languages.yml)是针对常见文件扩展名的一个有用来源。 - -## 语法高亮(可选) - -要为你的语言添加语法高亮,如果有的话,你还需要在`queries/highlights.scm`文件一个符号链接。 - -``` -$ cd vendored_parsers/highlights -$ ln -s ../tree-sitter-json/queries/highlights.scm json.scm -``` - -## 添加一个回归测试 - -最后,为你的语言添加一个回归测试,这样可以确保你的测试文件的输出不会意外改变。 - -回归测试文件存在于`sample_files/`中,其形式为 -`foo_1.abc`和`foo_2.abc`。 - -``` -$ nano simple_1.json -$ nano simple_2.json -``` - -运行回归测试脚本并更新`.expect`文件。 - -``` -$ ./sample_files/compare_all.sh -$ cp sample_files/compare.result sample_files/compare.expected -``` diff --git a/translation/zh-CN/manual-zh-CN/src/alternative_projects.md b/translation/zh-CN/manual-zh-CN/src/alternative_projects.md deleted file mode 100644 index 3c92d9e98..000000000 --- a/translation/zh-CN/manual-zh-CN/src/alternative_projects.md +++ /dev/null @@ -1,3 +0,0 @@ -# 其它项目 - -有许多不同的工具可以比较文件。本说明书的这一个部分讨论了其他影响到Difftastic的工具。 diff --git a/translation/zh-CN/manual-zh-CN/src/contributing.md b/translation/zh-CN/manual-zh-CN/src/contributing.md deleted file mode 100644 index 67c6d2f5e..000000000 --- a/translation/zh-CN/manual-zh-CN/src/contributing.md +++ /dev/null @@ -1,102 +0,0 @@ -# 贡献 - -## 构建 - -用[rustup](https://rustup.rs/)安装Rust,然后克隆代码。 - -``` -$ git clone git@github.com:Wilfred/difftastic.git -$ cd difftastic -``` - -Difftastic使用[Cargo](https://doc.rust-lang.org/cargo/)进行构建。 - -``` -$ cargo build -``` - -调试构建的速度明显比发布构建的速度慢。对于超过50行的文件,通常建议使用一个优化的构建。 - -``` -$ cargo build --release -``` - -## Manual说明书 - -这个网站是用[mdbook](https://github.com/rust-lang/mdBook/)。mdbook可以用Cargo安装。 - -``` -$ cargo install mdbook -``` - -然后你可以使用`mdbook`二进制文件来建立和在本地运行网站。 - -``` -$ cd manual -$ mdbook serve -``` - -## API文档 - -你可以浏览由rustdoc生成的内部API文档[在这里](https://difftastic.wilfred.me.uk/rustdoc/difft/)。 - -Difftastic的内部文档在docs.rs上没有提供,因为它[不支持二进制工具箱](https://difftastic.wilfred.me.uk/rustdoc/difft/)。 - -## 测试 - -``` -$ cargo test -``` - -在`sample_files/`中也有几个文件你可以使用。 - -测试difftastic的最好方法是在真实项目查看历史。设置`GIT_EXTERNAL_DIFF`指向你当前的构建。 - -例如,你可以在自己的源代码上运行Difftastic。 -``` -$ GIT_EXTERNAL_DIFF=./target/release/difft git log -p --ext-diff -- src -``` - -## 记录 - -Difftastic使用`pretty_env_logger`库来记录一些额外的调试信息。 - -``` -$ DFT_LOG=debug cargo run sample_files/old.jsx sample_files/new.jsx -``` - -请参阅[`env_logger`](https://docs.rs/env_logger/0.9.0/env_logger/)以获得完整的细节。 - -## 调试 - -如果你有一个特别慢的文件,你可以使用 [cargo-flamegraph](https://github.com/flamegraph-rs/flamegraph) 来查看是哪些函数慢的。 - -``` -$ CARGO_PROFILE_RELEASE_DEBUG=true cargo flamegraph --bin difft sample_files/slow_1.rs sample_files/slow_2.rs -``` - -内存的使用情况也是值得关注,因为图的遍历错误会导致巨大的内存消耗。 - -``` -$ /usr/bin/time -v ./target/release/difft sample_files/slow_1.rs sample_files/slow_2.rs -``` - -如果定时测量有噪音,Linux的`perf`工具将报告 执行的指令,这也是更加稳定的。 - -``` -$ perf stat ./target/release/difft sample_files/slow_1.rs sample_files/slow_2.rs -$ perf stat ./target/release/difft sample_files/typing_1.ml sample_files/typing_2.ml -``` - -还有很多剖析技术在[The Rust性能手册](https://nnethercote.github.io/perf-book/)中讨论了。 - -## 发布 - -使用Cargo创建一个新的版本,并在git中标记它。Difftastic有一个帮助脚本: - -``` -$ ./scripts/release.sh -``` - -现在你可以增加Cargo.toml中的版本,并在 -CHANGELOG.md加一个新的条目。 diff --git a/translation/zh-CN/manual-zh-CN/src/diffing.md b/translation/zh-CN/manual-zh-CN/src/diffing.md deleted file mode 100644 index 06c2b3553..000000000 --- a/translation/zh-CN/manual-zh-CN/src/diffing.md +++ /dev/null @@ -1,86 +0,0 @@ -# 差异分析 - -Difftastic将diff计算视作为有向无环图上的寻路问题。 - -## 图表示 - -图中的一个顶点代表两个语法树中的一个位置。 - -开始顶点的两个位置都指向两个树的第一个语法节点。结束顶点的两个位置都正好在两棵语法树的最后一个节点之后。 - -以`A`和`X A`比较为例: - -``` -START -+---------------------+ -| Left: A Right: X A | -| ^ ^ | -+---------------------+ - -END -+---------------------+ -| Left: A Right: X A | -| ^ ^| -+---------------------+ -``` - -从起始顶点开始,我们有两个选择: - -* 我们可以将左边的第一个语法节点标记为注意项,并推进到左边的下一个语法节点(即上面的顶点1)。 -* 我们可以将右边的第一个语法节点标记为注意项,并推进到右边的下一个语法节点上(即上面的顶点2)。 - -``` - START - +---------------------+ - | Left: A Right: X A | - | ^ ^ | - +---------------------+ - / \ - Novel atom L / \ Novel atom R -1 v 2 v -+---------------------+ +---------------------+ -| Left: A Right: X A | | Left: A Right: X A | -| ^ ^ | | ^ ^ | -+---------------------+ +---------------------+ -``` - - -选择"新原子R"到顶点2将是最佳选择。从顶点2,我们可以看到有三条路线通往终点。 - -``` - 2 - +---------------------+ - | Left: A Right: X A | - | ^ ^ | - +---------------------+ - / | \ - Novel atom L / | \ Novel atom R - v | v -+---------------------+ | +---------------------+ -| Left: A Right: X A | | | Left: A Right: X A | -| ^ ^ | | | ^ ^| -+---------------------+ | +---------------------+ - | | | - | Novel atom R | Nodes match | Novel atom L - | | | - | END v | - | +---------------------+ | - +-------->| Left: A Right: X A |<---------+ - | ^ ^| - +---------------------+ -``` - -## 比较路线 - -我们给每条边分配一个成本。将一个语法节点标记为新奇,比找到一个匹配的语法节点更糟糕,因此"新奇原子"边的成本比"语法节点匹配"边更高。 - -最佳路线是指从起始顶点到终端顶点成本最低的路线。 - -## 寻找最佳路线 - -Difftastic使用Dijkstra算法来寻找最佳(或称最低成本)的路线。 - -这种算法的一大优势是,我们不需要事先构建图。相对于语法节点的数量,构建整个图需要指数级的内存。相反顶点的邻居是在探索图的过程中构建的。 - -网上有很多解释Dijkstra的算法,但我特别推荐[Red - Blod Games的图搜索部分](https://www.redblobgames.com/pathfinding/a-star/introduction.html#dijkstra)。 diff --git a/translation/zh-CN/manual-zh-CN/src/fossil.md b/translation/zh-CN/manual-zh-CN/src/fossil.md deleted file mode 100644 index 02d0acf12..000000000 --- a/translation/zh-CN/manual-zh-CN/src/fossil.md +++ /dev/null @@ -1,29 +0,0 @@ -# Fossil - -[Fossil](https://fossil-scm.org/) 通过为当前存储库 [设置`diff-command`](https://fossil-scm.org/home/help?cmd=diff-command) 来支持外部 `diff` 命令: - -``` -fossil settings diff-command difft -``` - -如果你想对所有存储库使用 Difftastic,可以使用 `--global`: - -``` -fossil settings diff-command --global difft -``` - -## 在 Fossil 上跳过 Difftastic - -如果你已经将 Difftastic 设置为 Fossil 的 `diff` 命令,但想使用一次 Fossil 的内置差异分析工具,可以使用 `-i` 暂时跳过一次 Difftastic: - -``` -fossil diff -i -``` - -如果你想从某个存储库(或全局)移除 Difftastic,请使用 `unset` 命令: - -``` -fossil unset diff-command -``` - -`unset` 命令支持 `--global` 选项。 \ No newline at end of file diff --git a/translation/zh-CN/manual-zh-CN/src/git.md b/translation/zh-CN/manual-zh-CN/src/git.md deleted file mode 100644 index 5759858b7..000000000 --- a/translation/zh-CN/manual-zh-CN/src/git.md +++ /dev/null @@ -1,62 +0,0 @@ -# Git - -Git [支持使用外部差异分析工具](https://git-scm.com/docs/diff-config#Documentation/diff-config.txt-diffexternal)。你可以使用 `GIT_EXTERNAL_DIFF` 命令暂时地设置 diff 工具。 - -``` -$ GIT_EXTERNAL_DIFF=difft git diff -$ GIT_EXTERNAL_DIFF=difft git log -p --ext-diff -$ GIT_EXTERNAL_DIFF=difft git show e96a7241760319 --ext-diff -``` - -如果你想默认使用 Difftastic,可以使用 `git config`。 - -``` -# 仅为当前存储库设置 -$ git config diff.external difft - -# 为全局设置 -$ git config --global diff.external difft -``` - -在运行 `git config` 后,`git diff` 命令将会自动使用 `difft`。其他情况则需要使用 `--ext-diff` 来使用 `diff.external`。 - -``` -$ git diff -$ git log -p --ext-diff -$ git show e96a7241760319 --ext-diff -``` - -## git-difftool - -[git difftool](https://git-scm.com/docs/git-difftool) 是一个 Git 命令,用于使用不同差异分析工具来查看当前修改。如果你想要偶尔使用 Difftastic,这会非常有用。 - -添加下列内容到你的 `.gitconfig` 文件中,Difftastic 就会作为你的 diff 工具。 - -```ini -[diff] - tool = difftastic - -[difftool] - prompt = false - -[difftool "difftastic"] - cmd = difft "$LOCAL" "$REMOTE" -``` - -然后,你可以使用 `git difftool` 来用 Difftastic 查看当前修改。 - -``` -$ git difftool -``` - -我们还推荐使用下列设置来获得最好的差异分析工具体验。 - -```ini -# 对于较大的输出,和其它 Git 命令一样,使用分页器 -[pager] - difftool = true - -# `git dft` 比 `git difftool` 更加短小 -[alias] - dft = difftool -``` diff --git a/translation/zh-CN/manual-zh-CN/src/glossary.md b/translation/zh-CN/manual-zh-CN/src/glossary.md deleted file mode 100644 index 61d30a48e..000000000 --- a/translation/zh-CN/manual-zh-CN/src/glossary.md +++ /dev/null @@ -1,20 +0,0 @@ -# 词典 - -**原子**: 原子是Difftastic语法树结构中的一个项目,没有子项。它代表着字面量、变量名以及注释。 另见'list'。 - -**分隔符**: 即一个成对的语法。一个列表有一个开放定界符和一个封闭定界符,例如`[`和`]`。分隔符不可以是标点符号(例如,`begin`和`end`)以及空字符串(例如:infix语法转换为Difftastic的语法树)。 - -**LHS**: 即Left-hand side。Difftastic会对比两个文件,而LHS是指第一个文件。另见'RHS'。 - -**列表**: 列表是Difftastic语法树结构中的一个项目,它有一个开放定界符、子项和一个封闭定界符。它代表表达式和函数定义等东西。另见'atom'。 - -**注意项**: 一个增加或一个减少。如果语法只出现在被比较的两个项目中的一个,那么它就是一个注意项。 - -**RHS**: 即Right-hand side。Difftastic会对比两个文件,而RHS是指第一个文件。另见'LHS'。 - -**根**: 一个没有父节点的语法树。根代表被差异的文件中的顶级定义。 - -**语法节点**: Difftastic的语法树结构中的一个项目。可以是一个原子或一个列表。 - -**字符**: 一小段由Difftastic跟踪的语法(例如`$x`, -`function` 或 `]`),用于高亮显示和对齐显示。它是原子或者是一个非空的分隔符。 diff --git a/translation/zh-CN/manual-zh-CN/src/installation.md b/translation/zh-CN/manual-zh-CN/src/installation.md deleted file mode 100644 index 22dfea281..000000000 --- a/translation/zh-CN/manual-zh-CN/src/installation.md +++ /dev/null @@ -1,51 +0,0 @@ -# 安装 - -## 从二进制安装 - -Difftastic 将预先编译好的二进制文件 [提供到 GitHub releases](https://github.com/Wilfred/difftastic/releases) 。[更新日志](https://github.com/Wilfred/difftastic/blob/master/CHANGELOG.md) 描述了每个发行版的变更。 - -在以下平台上也可以使用软件包。 - -[![安装包状态](https://repology.org/badge/vertical-allrepos/difftastic.svg)](https://repology.org/project/difftastic/versions) - - -## 通过 homebrew 安装(macOS 或 Linux) - -Difftastic 可以使用 [Homebrew](https://formulae.brew.sh/formula/difftastic) 安装在 macOS 或 Linux 上。 - - -``` -$ brew install difftastic -``` - -## 从源码构建 - -### 要求 - -Difftastic 使用 Rust 编写,所以你需安装 Rust。我推荐使用 [rustup](https://rustup.rs/) 安装 Rust。Difftastic 要求 Rust 版本不低于 1.65。 - -你也需要一个支持 C++14 的 C++ 编译器。如果你正在使用 GCC,则 GCC 版本至少为 8。 - -### 构建 - -你可以下载并使用 Cargo(Rust 的一部分)构建 [Difftastic on -crates.io](https://crates.io/crates/difftastic)。 - -``` -$ cargo install --locked difftastic -``` - -Difftastic 使用 `cc` 程序箱来构建 C/C++ 的依赖关系,这使你能通过环境变量 `CC` 与 `CXX` 来控制使用的编译器(参照 [cc -文档](https://github.com/alexcrichton/cc-rs#external-configuration-via-environment-variables))。 - -参考 [贡献](./contributing.md) 来查看有关构建的说明。 - -## (可选)安装 MIME 数据库 - -如果有一个 MIME 数据库,Difftastic 将使用它来更准确地检测二进制文件。MIME 数据库在使用 `file` 命令时也需要被调用,因此你可能已经安装了它。 - -MIME 数据库的路径 [在 XDG 的规范下](https://specifications.freedesktop.org/shared-mime-info-spec/0.11/ar01s03.html): - -* `/usr/share/mime/magic` -* `/usr/local/share/mime/magic` -* `$HOME/.local/share/mime/magic` diff --git a/translation/zh-CN/manual-zh-CN/src/introduction.md b/translation/zh-CN/manual-zh-CN/src/introduction.md deleted file mode 100644 index f5291cc67..000000000 --- a/translation/zh-CN/manual-zh-CN/src/introduction.md +++ /dev/null @@ -1,55 +0,0 @@ -# 简介 - -Difftastic 是一个根据文件语法进行比较的结构化比较工具。它 [支持超过 30 种编程语言](./languages_supported.html)。当你使用时,便会知道它有多么 *棒*。 - -Difftastic 是一款开源软件(使用 MIT 许可证),你可以 [在 GitHub 上查看其源代码](https://github.com/wilfred/difftastic)。 - -本说明书描述当前版本 DFT_VERSION_HERE。[更新日志](https://github.com/Wilfred/difftastic/blob/master/CHANGELOG.md) 会记录每个版本的新特性与 bug 的修复。 - -*如果你正寻找其他语言的说明书,我们同样提供了 [英文版](https://difftastic.wilfred.me.uk/)。* - -## 语法差异分析 - -Difftastic [检测编程语言](./usage.html#language-detection)、解析代码,并比较语法树。以下是例子。 - -``` -// old.rs -let ts_lang = guess(path, guess_src).map(tsp::from_language); -``` - -``` -// new.rs -let ts_lang = language_override - .or_else(|| guess(path, guess_src)) - .map(tsp::from_language); -``` - -
$ difft old.rs new.rs
-
-1 1 let ts_lang = language_override
-. 2     .or_else(|| guess(path, guess_src))
-. 3     .map(tsp::from_language);
-
-
- -注意 Difftastic 是如何识别 `.map` 没有变化的,尽管它在带有空格的新行上。 - -面对行的差异分析表现则会很不理想。 - -
$ diff -u old.rs new.rs
-
-@@ -1 +1,3 @@
--let ts_lang = guess(path, guess_src).map(tsp::from_language);
-+let ts_lang = language_override
-+    .or_else(|| guess(path, guess_src))
-+    .map(tsp::from_language);
-
-
- -一些文本差异分析工具也会突出单词的变化(如 GitHub 或 git 的 `--word-diff`),但它们仍无法理解代码本身。Difftastic 永远会找到匹配的定界符:你可以看到 `or_else` 结尾处的 `)` 已被突出显示。 - -## 备用的文本差异分析 - -如果 Difftastic 不能理解输入文件,它将用常规的面向行的文本差异分析与单词高亮显示。 - -同时,当输入的文件较大时,Difftastic 也会使用面向行的文本差异分析。 diff --git a/translation/zh-CN/manual-zh-CN/src/languages_supported.md b/translation/zh-CN/manual-zh-CN/src/languages_supported.md deleted file mode 100644 index 1d68e85ad..000000000 --- a/translation/zh-CN/manual-zh-CN/src/languages_supported.md +++ /dev/null @@ -1,59 +0,0 @@ -# 支持的语言 - -本页列出了 Difftastic 支持的所有语言。你也可以用 `difft --list-languages` 查看你当前安装的版本所支持的语言。 - -## 编程语言 - -| 语言 | 使用的解析器 | -|-----------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------| -| Bash | [tree-sitter/tree-sitter-bash](https://github.com/tree-sitter/tree-sitter-bash) | -| Apex | [aheber/tree-sitter-sfapex](https://github.com/aheber/tree-sitter-sfapex) | -| C | [tree-sitter/tree-sitter-c](https://github.com/tree-sitter/tree-sitter-c) | -| C++ | [tree-sitter/tree-sitter-cpp](https://github.com/tree-sitter/tree-sitter-cpp) | -| C# | [tree-sitter/tree-sitter-c-sharp](https://github.com/tree-sitter/tree-sitter-c-sharp) | -| Clojure | [sogaiu/tree-sitter-clojure](https://github.com/sogaiu/tree-sitter-clojure) ([branched](https://github.com/sogaiu/tree-sitter-clojure/tree/issue-21)) | -| CMake | [uyha/tree-sitter-cmake](https://github.com/uyha/tree-sitter-cmake) | -| Common Lisp | [theHamsta/tree-sitter-commonlisp](https://github.com/theHamsta/tree-sitter-commonlisp) | -| Dart | [UserNobody14/tree-sitter-dart](https://github.com/UserNobody14/tree-sitter-dart) | -| Elixir | [elixir-lang/tree-sitter-elixir](https://github.com/elixir-lang/tree-sitter-elixir) | -| Elm | [elm-tooling/tree-sitter-elm](https://github.com/elm-tooling/tree-sitter-elm) | -| Erlang | [WhatsApp/tree-sitter-erlang](https://github.com/WhatsApp/tree-sitter-erlang) | -| Emacs Lisp | [wilfred/tree-sitter-elisp](https://github.com/Wilfred/tree-sitter-elisp) | -| Fish | [ram02z/tree-sitter-fish](https://github.com/ram02z/tree-sitter-fish) | -| Gleam | [gleam-lang/tree-sitter-gleam](https://github.com/gleam-lang/tree-sitter-gleam) | -| Go | [tree-sitter/tree-sitter-go](https://github.com/tree-sitter/tree-sitter-go) | -| Hare | [ecmma/tree-sitter-hare](https://git.sr.ht/~ecmma/tree-sitter-hare) | -| Haskell | [tree-sitter/tree-sitter-haskell](https://github.com/tree-sitter/tree-sitter-haskell) | -| Janet | [sogaiu/tree-sitter-janet-simple](https://github.com/sogaiu/tree-sitter-janet-simple) | -| Java | [tree-sitter/tree-sitter-java](https://github.com/tree-sitter/tree-sitter-java) | -| JavaScript, JSX | [tree-sitter/tree-sitter-javascript](https://github.com/tree-sitter/tree-sitter-javascript) | -| Julia | [tree-sitter/tree-sitter-julia](https://github.com/tree-sitter/tree-sitter-julia) | -| Kotlin | [fwcd/tree-sitter-kotlin](https://github.com/fwcd/tree-sitter-kotlin) | -| Lua | [nvim-treesitter/tree-sitter-lua](https://github.com/nvim-treesitter/tree-sitter-lua) | -| Make | [alemuller/tree-sitter-make](https://github.com/alemuller/tree-sitter-make) | -| Nix | [cstrahan/tree-sitter-nix](https://github.com/cstrahan/tree-sitter-nix) | -| OCaml | [tree-sitter/tree-sitter-ocaml](https://github.com/tree-sitter/tree-sitter-ocaml) | -| Perl | [ganezdragon/tree-sitter-perl](https://github.com/ganezdragon/tree-sitter-perl) | -| PHP | [tree-sitter/tree-sitter-php](https://github.com/tree-sitter/tree-sitter-php) | -| Python | [tree-sitter/tree-sitter-python](https://github.com/tree-sitter/tree-sitter-python) | -| QML | [tree-sitter/tree-sitter-qmljs](https://github.com/yuja/tree-sitter-qmljs) | -| R | [r-lib/tree-sitter-r](https://github.com/r-lib/tree-sitter-r) | -| Racket | [6cdh/tree-sitter-racket](https://github.com/6cdh/tree-sitter-racket) | -| Ruby | [tree-sitter/tree-sitter-ruby](https://github.com/tree-sitter/tree-sitter-ruby) | -| Rust | [tree-sitter/tree-sitter-rust](https://github.com/tree-sitter/tree-sitter-rust) ([forked](https://github.com/Wilfred/tree-sitter-rust/tree/non_special_token)) | -| Scala | [tree-sitter/tree-sitter-scala](https://github.com/tree-sitter/tree-sitter-scala) | -| SQL | [m-novikov/tree-sitter-sql](https://github.com/m-novikov/tree-sitter-sql) | -| Swift | [alex-pinkus/tree-sitter-swift](https://github.com/alex-pinkus/tree-sitter-swift) | -| TypeScript, TSX | [tree-sitter/tree-sitter-typescript](https://github.com/tree-sitter/tree-sitter-typescript) | -| Zig | [maxxnino/tree-sitter-zig](https://github.com/maxxnino/tree-sitter-zig) | - -## 结构化文本格式 -| 语言 | 使用的解析器 | -|----------|-----------------------------------------------------------------------------------| -| CSS | [tree-sitter/tree-sitter-css](https://github.com/tree-sitter/tree-sitter-css) | -| HCL | [MichaHoffmann/tree-sitter-hcl](https://github.com/MichaHoffmann/tree-sitter-hcl) | -| HTML | [tree-sitter/tree-sitter-html](https://github.com/tree-sitter/tree-sitter-html) | -| JSON | [tree-sitter/tree-sitter-json](https://github.com/tree-sitter/tree-sitter-json) | -| Newick | [delehef/tree-sitter-newick](https://github.com/delehef/tree-sitter-newick) | -| TOML | [ikatyang/tree-sitter-toml](https://github.com/ikatyang/tree-sitter-toml) | -| YAML | [ikatyang/tree-sitter-yaml](https://github.com/ikatyang/tree-sitter-yaml) | diff --git a/translation/zh-CN/manual-zh-CN/src/mercurial.md b/translation/zh-CN/manual-zh-CN/src/mercurial.md deleted file mode 100644 index 5adefe08e..000000000 --- a/translation/zh-CN/manual-zh-CN/src/mercurial.md +++ /dev/null @@ -1,33 +0,0 @@ -# Mercurial - -Mercurial 在使用 Extdiff 拓展时,[支持使用外部差异分析工具](https://www.mercurial-scm.org/wiki/ExtdiffExtension)。你可以在 `.hgrc` 文件中添加 `extensions` 条目来启用它。 - -``` -[extensions] -extdiff = -``` - -接下来,你可以运行 `hg extdiff -p difft` 命令,但不是 `hg diff` 命令(假定 `difft` 二进制文件已经存放在 `$PATH` 中)。 - -您还可以定义一个别名,用 hg 运行 Difftastic。将以下内容添加到您的 `.hgrc` 中,以使用 `hg dft` 命令运行 Difftastic。 - -``` -[extdiff] -cmd.dft = difft -# 你可以添加更多选项,它们将被传递至命令行,例如: -# opts.dft = --background light -``` - -`hg dft` 也支持 `hg diff` 的所有选项。例如,`hg dft --stat` 会显示更改行的统计信息,`hg dft -r 42 -r 45` 会显示两个修订版之间的差异。 - -## hg log -p - -Mercurial 不能改变默认的差异工具,至少就作者所知。 - -如果你想查看最近一次提交的差异,可以使用下面的命令。 - -``` -hg dft -r .^ -r . -``` - -这就等同于`hg log -l 1 -p`,尽管它不显示提交信息。 diff --git a/translation/zh-CN/manual-zh-CN/src/parser_vendoring.md b/translation/zh-CN/manual-zh-CN/src/parser_vendoring.md deleted file mode 100644 index 30783cff0..000000000 --- a/translation/zh-CN/manual-zh-CN/src/parser_vendoring.md +++ /dev/null @@ -1,19 +0,0 @@ -# 包管理 - -## Git Subtrees - -Tree-sitter有时被打包在npm上,有时被打包在crates.io上,并且它们的发布频率不一样。Difftastic使用git subtrees(而不是git submodules)来追踪解析器。 - -## 升级解析器 - -如果要更新解析器,可以从上游的git仓库拉取提交。例如,下面的命令将更新Java解析器: - -``` -$ git subtree pull --prefix=vendored_parsers/tree-sitter-java git@github.com:tree-sitter/tree-sitter-java.git master -``` - -如果要查看每个解析器最后一次更新的时间,请使用以下的Shell命令: - -``` -$ for d in $(git log | grep git-subtree-dir | tr -d ' ' | cut -d ":" -f2 | sort); do echo "$d"; git log --pretty=" %cs" -n 1 $d; done -``` diff --git a/translation/zh-CN/manual-zh-CN/src/parsing.md b/translation/zh-CN/manual-zh-CN/src/parsing.md deleted file mode 100644 index 7d64095ec..000000000 --- a/translation/zh-CN/manual-zh-CN/src/parsing.md +++ /dev/null @@ -1,70 +0,0 @@ -# 解析代码 - -Difftastic会使用[tree-sitter](https://tree-sitter.github.io/tree-sitter/) 来建立一个语法树。然后,该语法树被转换为一个可以用来对比差异的简化版语法树。 - -## 使用Tree-sitter解析代码 - -Difftastic依靠tree-sitter来理解语法。你可以使用`--dump-ts`来查看tree-sitter的语法树。 - -``` -$ difft --dump-ts sample_files/javascript_simple_1.js | head -program (0, 0) - (7, 0) - comment (0, 0) - (0, 8) "// hello" - expression_statement (1, 0) - (1, 6) - call_expression (1, 0) - (1, 5) - identifier (1, 0) - (1, 3) "foo" - arguments (1, 3) - (1, 5) - ( (1, 3) - (1, 4) "(" - ) (1, 4) - (1, 5) ")" - ; (1, 5) - (1, 6) ";" - expression_statement (2, 0) - (2, 6) -``` - -## 简化的语法 - -Difftastic将tree-sitter语法树转换为简化版的语法树。语法树是一种统一的表示方式,其中所有东西都是原子(例如,整数、注释、变量名)或者是一个列表(由开放分界符、子句和关闭分界符组成)以及分隔符。 - -`--dump-syntax`将显示出当前文件所对应的语法树。 - -``` -$ difft --dump-syntax sample_files/before.js -[ - Atom id:1 { - content: "// hello", - position: "0:0-8", - }, - List id:2 { - open_content: "", - open_position: "1:0-0", - children: [ - ... -``` - -### 转换过程 - -Difftastic语法树的简单表达方式使得差异分析变得更加容易。Difftastic是通过一种递归树的行走方式来将tree-sitter树进行简化,将tree-sitter的节点视作原子来处理。但有两个例外。 - -(1) Tree-sitter语法树有时会包括不需要的一些结构,有些语法会认为字符串是一种单一的字符,而有些则会将字符串视作为复杂的结构,此时的分隔符就会将字符串分割开。 - -`tree-sitter_parser.rs`使用`atom_nodes`来标记特定的tree-sitter节点为平原子,即使该节点存在子节点。 - -(2) Tree-sitter分析树包括开放和关闭定界符作为其代码。列表`[1]`将有一个包括`[`和`]`的节点的语法树。 - -``` -$ echo '[1]' > example.js -$ difft --dump-ts example.js -program (0, 0) - (1, 0) - expression_statement (0, 0) - (0, 3) - array (0, 0) - (0, 3) - [ (0, 0) - (0, 1) "[" - number (0, 1) - (0, 2) "1" - ] (0, 2) - (0, 3) "]" -``` - -`tree_sitter_parser.rs`使用`open_delimiter_tokens`来确保`[`和`]`被用作包围列表内容的分隔符,而不会将其转换为原子。 - -Difftastic可以将出现简化语法树中不同部分的原子进行匹配。例如,如果一个`[`被当作一个原子,Difftastic可能会在其他地方将其与另一个`]`进行匹配。如果开放和关闭分界符的数量不同,最终的差异分析结果将会是不平衡的。 - -### Lossy Syntax Trees简化的语法树 - -简化的语法树只存储节点内容与节点的位置,不会存储节点之间的空白,而且在差异分析的过程中,空格将会被忽略。 diff --git a/translation/zh-CN/manual-zh-CN/src/robots.txt b/translation/zh-CN/manual-zh-CN/src/robots.txt deleted file mode 100644 index c2a49f4fb..000000000 --- a/translation/zh-CN/manual-zh-CN/src/robots.txt +++ /dev/null @@ -1,2 +0,0 @@ -User-agent: * -Allow: / diff --git a/translation/zh-CN/manual-zh-CN/src/tree_diffing.md b/translation/zh-CN/manual-zh-CN/src/tree_diffing.md deleted file mode 100644 index e259da8d0..000000000 --- a/translation/zh-CN/manual-zh-CN/src/tree_diffing.md +++ /dev/null @@ -1,84 +0,0 @@ -# 树状差异分析 - -本页总结了一些其他可用的树形差异分析工具。 - -如果你很着急,可以先看看Autochrome。它的能力很强,并且对设计有着很好的描述。 - -如果你对学术文献的摘要感兴趣,[这个帖子](http://useless-factor.blogspot.com/2008/01/matching-diffing-and-merging-xml.html)(和它[附带的论文](http://useless-factor.blogspot.com/2008/01/matching-diffing-and-merging-xml.html)--在CC BY-NC的许可下可以被复制)将是一个很好的资源。 - -## json-diff (2012) - -语言:JSON -算法:Pairwise comparison -输出:CLI colours - -[json-diff](https://github.com/andreyvit/json-diff)展示了JSON文件的结构层面的差异分析。如果两者是不完全匹配的,那么它们的子树将是完全不同。例如,`"foo"`和`["foo"]`是完全不同的。 - -可以注意的是,json-diff的结果显示十分方便查看。 - -## GumTree (2014) - -语言:[约有10种编程语言](https://github.com/GumTreeDiff/gumtree/wiki/Languages) -分析器:多种,包括 [srcML](https://www.srcml.org/) -算法:Top-down,随后bottom-up -输出:HTML,Swing GUI或者text - -[GumTree](https://github.com/GumTreeDiff/gumtree)可以分析多种编程语言,并且进行基于树结构的差异分析,输出一个HTML的结果界面。 - -GumTree算法在Falleri等人的相关论文《细粒度源码差异分析》中有所描述([DOI](http://doi.acm.org/10.1145/2642937.2642982), -[PDF](https://hal.archives-ouvertes.fr/hal-01054552/document))。它对相同的子树进行贪婪的自下而上的搜索,随后进行自下而上的搜索来匹配其余的子树。 - -## Tree Diff (2017) - -语言:S-表达式数据格式 -算法:A*搜索 -输出:合并后的S-表达式文件 - -Tristan Hume在他2017年实习期间和在Jane Street期间写了一个树状差分算法。源代码是不可以用的,但是[他写了一篇博客](https://thume.ca/2017/06/17/tree-diffing/)来对该设计进行了深入讨论。 - -该项目找到了Jane Street用作配置文件的s-表达式文件之间的最小差异。它使用了A*搜索来找到他们之间最小的差异,兵建立一个具有`:date-switch`进行标记差异的新的s-表达式文件。 - -(Jane Street一样有patdiff,但那似乎是一个面向行的差异分析,并不带着一些空格及整数差异显示。这个工具它并不理解在`"foo "`中的空格是具有意义的。) - -## Autochrome (2017) - -语言:Clojure -分析器:Custom,并保留注释 -算法:Dijkstra算法(A*搜索的先前版本) -输出:HTML - -[Autochrome](https://fazzone.github.io/autochrome.html)使用了一个定制的、保留注释的解析器来分析Clojure。Autochrome使用Dijkstra算法来比较语法树之间的差异。 - -Auto chrome的网页包括该算法的工作实例以及对该设计权衡的讨论。这是一个用来了解树形差异分析的重要资源。 - -## graphtage (2020) - -语言:JSON, XML, HTML, YAML, plist, and CSS -解析器:json5, pyYAML, ignores comments -算法:Levenshtein距离 -输出:CLI colours - -[graphtage](https://blog.trailofbits.com/2020/08/28/graphtage/)通过将结构化数据解析为通用文件格式,随后进行差异分析。它甚至允许比较JSON文件和YAML文件之间的区别。 - -与json-diff一样,它不认为 `["foo"]`和`"foo"`之间有任何相似之处。 - -## Diffsitter (2020) - -解析器:[Tree-sitter](https://tree-sitter.github.io/tree-sitter/) -算法:LCS(Longest-common-subsequence) -输出:CLI colours - -[Diffsitter](https://github.com/afnanenayet/diffsitter)是另一个使用了tree-sitter解析器的差异分析工具。它使用了[LCS分析语法树中的子树](https://github.com/afnanenayet/diffsitter/blob/b0fd72612c6fcfdb8c061d3afa3bea2b0b754f33/src/ast.rs#L310-L313)。 - -## sdiff (2021) - -语言:Scheme -解析器:Scheme内置的`read`,并忽略注释 -算法:Chawathe论文中的MH-Diff -输出:CLI colours - -[Semantically meaningful S-expression diff: Tree-diff for lisp source -code](https://archive.fosdem.org/2021/schedule/event/sexpressiondiff/) -在FOSDEM 2021中被发表。 - - diff --git a/translation/zh-CN/manual-zh-CN/src/tricky_cases.md b/translation/zh-CN/manual-zh-CN/src/tricky_cases.md deleted file mode 100644 index 19bd6aae6..000000000 --- a/translation/zh-CN/manual-zh-CN/src/tricky_cases.md +++ /dev/null @@ -1,383 +0,0 @@ -# 棘手的例子 - -树状差异分析有时具有挑战性。本页展示了开发过程中观察到的困难情况和处理结果。 - -并非所有这些情况在 Difftastic 中都能很好地工作。 - -## 添加定界符 - -``` -;; Before -x - -;; After -(x) -``` - -可能输出:(x) - -理想输出:(x) - -这十分棘手,因为 `x` 改变了在树中的深度,但其本身却未发生改变。 - -并不是所有的树状差异分析算法可以处理这个例子。同时仔细地展示出范例是具有挑战性的:我们希望高亮已改变的定界符,而非他们的内容。这同样在更大的表达式中具有挑战性。 - -**Difftastic**:Difftastic 即使认为节点在不同深度,在这种情况下也能实现预期结果。 - -## 改变定界符 - -``` -;; Before -(x) - -;; After -[x] -``` - -理想输出:(x), [x] - -正如这个例子,我们想要高亮定界符而非 `x` 这个内容。 - -**Difftastic**:通过树状差异分析,Difftastic 正确处理这个问题。 - -## 扩展定界符 - -``` -;; Before -(x) y - -;; After -(x y) -``` - -可能输出 1:(x) y, (x y) - -可能输出 2:(x) y, (x y) - -目前还不清楚在这种情况下,哪个结果更好。 - -**Difftastic**:Difftastic 目前显示结果 2,但这种情况下对成本模型很敏感。一些以前版本的 Difftastic 显示结果 1。 - -## 缩小定界符 - -``` -;; Before -(x y) - -;; After -(x) y -``` - -这与扩展定界符的情况类似。 - -## 使定界符不连贯 - -``` -;; Before -(foo (bar)) - -;; After -(foo (novel) (bar)) -``` - -理想输出:(foo (novel) (bar) - -很容易会变成 (foo (novel) (bar)), -其中后一组的定界符会被选中。 - -## 重新组织大节点 - -``` -;; Before -[[foo]] -(x y) - -;; After -([[foo]] x y) -``` - -我们想高亮 `[[foo]]` 被移到了括号内。然而,一个简单的语法差异者更倾向于认为在前面删除 `()` 并在后面增加 `()`,因为这是最小的差异表现(见[议题 #44](https://github.com/Wilfred/difftastic/issues/44))。 - -## 在列表内重新排列 - -``` -;; Before -(x y) - -;; After -(y x) -``` - -理想输出:(y x) - -我们想高亮列表内容,而非定界符。 - -## 中间插入 - -``` -// Before -foo(bar(123)) - -// After -foo(extra(bar(123))) -``` - -理想输出:foo(extra(bar(123))) - -我们想把 `foo` 和 `bar` 看作是未改变的。这种情况对树进行自下而上然后自上而下匹配的衍合算法具有挑战性。 - -## 标点符号元素 - -``` -// Before -foo(1, bar) - -// After -foo(bar, 2) -``` - -可能输出:foo(bar, 2) - -理想输出:foo(bar, 2) - -`()` 内有两个元素,我们可以认为 `bar` 和 `,` 中有一个未改变(但不能认为两者都不改变,因为它们已经重新排序)。 - -我们想把 `bar` 看作是未改变的,因为它相比于 `,` 元素更加重要。在语言不可知的方式下完成这一点存在困难,所以 Difftastic 有一个小的低优先级标点符号元素列表。 - -## 滑块(平移) - -在基于文本的差异分析中,滑块是一个常见的问题,即行与行之间以混乱的方式进行匹配。 - -它们通常看起来像这样。差异分析必须任意选择一个包含分隔符的行,但它选择了错误的行。 - -``` -+ } -+ -+ function foo () { - } -``` - -git-diff 有一些启发式方法(比如 Patience Diff)降低这种风险,但这个问题仍可能发生。 - -在树状差异分析时也有类似的问题。 - -``` -;; Before -A B -C D - -;; After -A B -A B -C D -``` - -可能输出: - -
A B
-A B
-C D
-
- -理想输出: - -
A B
-A B
-C D
-
- -理想情况下,我们更期望将连续节点标记为新的。从最长共子序列算法(LCS)看,这两个选择等价。 - -## 滑块(嵌套) - -``` -// Before -old1(old2) - -// After -old1(new1(old2)) -``` - -可能输出:old1(new1(old2)) - -理想输出:old1(new1(old2)) - -正确的答案是取决于语言。大多数语言希望优先使用内部定界符,而 Lisps 与 JSON 则期望使用外部定界符。 - -## 最小化深度改变 - -``` -// Before -if true { - foo(123); -} -foo(456); - -// After -foo(789); -``` - -我们认为 `foo(123)` 与 `foo(456)` 中,哪个与 `foo(789)` 匹配?Difftastic 优先考虑 `foo(456)`,因为其优先考虑相同嵌套深度的节点。 - -## 有少量相似处的替代做法 - -``` -// Before -function foo(x) { return x + 1; } - -// After -function bar(y) { baz(y); } -``` - -可能结果:function bar(y) { baz(y); } - -在这个例子中,我们删除了一个函数并写了一个完全不同的函数。树状结构差异分析可能会匹配 `function` 和外部定界符,从而导致高亮许多令人困惑的小变化。 - -与滑块一样,替代问题也可能发生在基于文本的行差中。如果有少量的共同行,行差就会陷入困境。但树状结构差异分析的精确、细化行为会使这个问题更加普遍。 - -## 匹配注释中的子字符串 - -``` -// Before -/* The quick brown fox. */ -foobar(); - -// After -/* The slow brown fox. */ -foobaz(); -``` - -`foobar` 和 `foobaz` 完全不同,它们的共同前缀 `fooba` 不应该被匹配。然而,为注释匹配共同的前缀或后缀是可取的。 - -## 多行注释 - -``` -// Before -/* Hello - * World. */ - -// After -if (x) { - /* Hello - * World. */ -} -``` - -这两个注释的内部内容在技术上是不同的。然而,我们期望把它们当作是相同的。 - -## 文档注释的换行 - -块状评论的前缀并没有什么意义。 - -``` -// Before -/* The quick brown fox jumps - * over the lazy dog. */ - -// After -/* The quick brown fox immediately - * jumps over the lazy dog. */ -``` - -里面的内容已经从 `jumps * over` 变成了 `immediately * jumps over`。然而,`*` 是装饰性的,我们并不关心它的移动。 - -## 长字符串的小变化 - -``` -// Before -"""A very long string -with lots of words about -lots of stuff.""" - -// After -"""A very long string -with lots of NOVEL words about -lots of stuff.""" -``` - -将整个字符串字头高亮为被删除并被一个新的字符串字头取代是正确的。然而,这让人很难看出实际改变了什么。 - -很明显,变量名应该被元素化处理,并且注释是安全的,可以显示子字符串的变化。但不清楚如何处理一个 20 行字符串字面值的小变化。 - -在空格上分割字符串并加以区别很具有挑战性,但用户仍期望知道字符串内部的空白何时改变。`" "` 与 `" "` 是不同的。 - -## 自动格式化工具的拼写 - -``` -// Before -foo("looooong", "also looooong"); - -// Before -foo( - "looooong", - "novel", - "also looooong", -); -``` - -自动格式化(例如 [Prettier](https://prettier.io/))有时会在格式化时添加或删除标点符号,其中逗号和括号最常见。 - -语法差异可以忽略空白处的变化,但它必须假定标点符号有意义。这可能导致标点符号的变化被突出显示,而这可能与相关的内容变化相差甚远。 - -## 新空行 - -空行对于语法差异分析来说是一种挑战。我们要比较的是语法标记,所以我们不会看到空行。 - -``` -// Before -A -B - -// After -A - -B -``` - -一般来说,我们期望语法差异能够忽略空行。在第一个例子中,这应该不会显示任何变化。 - -这有时是有问题的,因为它可以会意外地隐藏被重新格式化的代码。 - -``` -// Before -A -B - -// After -A -X - -Y -B -``` - -在第二个例子中,我们插入了 X 和 Y 以及一个空行。我们想把空行作为一个补充来高亮。 - -``` -// Before -A - - -B - -// After -A -X -B -``` - -在第三个例子中,语法差异分析只看到了一个增加。从用户角度来看,也有两个空行被删除。 - -## 无效语法 - -我们不能保证我们得到的输入是有效的语法。即使代码是有效的,它也可能使用解析器不支持的语法。 - -**Difftastic**:如果发生任何解析错误,Difftastic 将退回到基于文本的差异,以避免差异不完整的语法树。发生这种情况时,文件头会报告错误计数。 - -``` -$ difft sample_files/syntax_error_1.js sample_files/syntax_error_2.js -sample_files/syntax_error_after.js --- Text (2 errors, exceeded DFT_PARSE_ERROR_LIMIT) -... -``` - -用户可以选择通过将 `DFT_PARSE_ERROR_LIMIT` 设置为一个更大的值,加入语法差异分析。在这种模式下,Difftastic 会将树状差异分析的错误节点看作元素,并像通常一样进行树状差异分析。 diff --git a/translation/zh-CN/manual-zh-CN/src/usage.md b/translation/zh-CN/manual-zh-CN/src/usage.md deleted file mode 100644 index 068e17f31..000000000 --- a/translation/zh-CN/manual-zh-CN/src/usage.md +++ /dev/null @@ -1,74 +0,0 @@ -# 使用方法 - -## 文件参数 - -### 比较文件 - -```bash -$ difft FIRST-FILE SECOND-FILE - -$ difft sample_files/simple_1.js sample_files/simple_2.js -``` - -### 比较文件夹 - -```bash -$ difft FIRST-DIRECTORY SECOND-DIRECTORY - -# For example: -$ difft sample_files/dir_1/ sample_files/dir_2/ -``` - -Difftastic 会递归地浏览这两个文件夹,对同名的文件进行差异分析。 - -对比的文件夹间有许多未改变的文件时,`--skip-unchanged` 选项会十分有用。 - -### 从 stdin 读取 - -您可以通过指定 `-` 作为文件路径从标准输入(stdin)读取文件。 - -```bash -$ difft - SECOND-FILE - -$ cat sample_files/simple_1.js | difft - sample_files/simple_2.js -``` - -### 带冲突标记的文件 - -*(在 0.50 版本新增)* - -如果你有一个带 `<<<<<<<` 冲突标记的文件,可以将它作为一个参数传入 Difftastic。Difftastic 会构建和比较文件的两个状态。 - -```bash -$ difft FILE-WITH-CONFLICTS - -$ difft sample_files/conflicts.el -``` - -## 语言检测 - -Difftastic 根据文件的扩展名、文件名和第一行的内容猜测文件所用的语言。 - -你可以通过 `--override` 选项覆盖语言检测。如果输入的文件有所设定的后缀, Difftastic 将会处理它们,并且忽略其他语言。 - -```bash -$ difft --override=GLOB:NAME FIRST-FILE SECOND-FILE - -$ difft --override=*.h:c sample_files/preprocessor_1.h sample_files/preprocessor_2.h -``` - -## 选项 - -Difftastic 包括一系列命令行选项,你可以使用 `difft --help` 获得完整列表。 - -Difftastic 也可以用环境变量进行配置,这同样可以在 `--help` 中看到。 - -例如,`DFT_BACKGROUND=light` 相当于 `--background=light`。这在使用 VCS 工具(例如 Git)时会很有用,因为此时不能直接调用 `difft` 二进制文件。 - -## 退出状态码 - -2:Difftastic 收到了无效参数。这包括用法无效(如参数数量不对)、无法读取路径(如路径不存在或权限不足)。 - -1:使用 `--exit-code` 选项时,Difftastic 在发现任何语法变化(文本文件)或字节变化(二进制文件)。 - -0:所有其他情况。 diff --git a/tui/package.json b/tui/package.json index fc6ef39bf..051bccad4 100644 --- a/tui/package.json +++ b/tui/package.json @@ -1,6 +1,7 @@ { "name": "@diffr/tui", "private": true, + "license": "MIT", "type": "module", "scripts": { "start": "bun run packages/hunk/src/main.tsx", diff --git a/vendored_parsers/tree-sitter-janet-simple/LICENSE b/vendored_parsers/tree-sitter-janet-simple/LICENSE new file mode 100644 index 000000000..0e259d42c --- /dev/null +++ b/vendored_parsers/tree-sitter-janet-simple/LICENSE @@ -0,0 +1,121 @@ +Creative Commons Legal Code + +CC0 1.0 Universal + + CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE + LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN + ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS + INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES + REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS + PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM + THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED + HEREUNDER. + +Statement of Purpose + +The laws of most jurisdictions throughout the world automatically confer +exclusive Copyright and Related Rights (defined below) upon the creator +and subsequent owner(s) (each and all, an "owner") of an original work of +authorship and/or a database (each, a "Work"). + +Certain owners wish to permanently relinquish those rights to a Work for +the purpose of contributing to a commons of creative, cultural and +scientific works ("Commons") that the public can reliably and without fear +of later claims of infringement build upon, modify, incorporate in other +works, reuse and redistribute as freely as possible in any form whatsoever +and for any purposes, including without limitation commercial purposes. +These owners may contribute to the Commons to promote the ideal of a free +culture and the further production of creative, cultural and scientific +works, or to gain reputation or greater distribution for their Work in +part through the use and efforts of others. + +For these and/or other purposes and motivations, and without any +expectation of additional consideration or compensation, the person +associating CC0 with a Work (the "Affirmer"), to the extent that he or she +is an owner of Copyright and Related Rights in the Work, voluntarily +elects to apply CC0 to the Work and publicly distribute the Work under its +terms, with knowledge of his or her Copyright and Related Rights in the +Work and the meaning and intended legal effect of CC0 on those rights. + +1. Copyright and Related Rights. A Work made available under CC0 may be +protected by copyright and related or neighboring rights ("Copyright and +Related Rights"). Copyright and Related Rights include, but are not +limited to, the following: + + i. the right to reproduce, adapt, distribute, perform, display, + communicate, and translate a Work; + ii. moral rights retained by the original author(s) and/or performer(s); +iii. publicity and privacy rights pertaining to a person's image or + likeness depicted in a Work; + iv. rights protecting against unfair competition in regards to a Work, + subject to the limitations in paragraph 4(a), below; + v. rights protecting the extraction, dissemination, use and reuse of data + in a Work; + vi. database rights (such as those arising under Directive 96/9/EC of the + European Parliament and of the Council of 11 March 1996 on the legal + protection of databases, and under any national implementation + thereof, including any amended or successor version of such + directive); and +vii. other similar, equivalent or corresponding rights throughout the + world based on applicable law or treaty, and any national + implementations thereof. + +2. Waiver. To the greatest extent permitted by, but not in contravention +of, applicable law, Affirmer hereby overtly, fully, permanently, +irrevocably and unconditionally waives, abandons, and surrenders all of +Affirmer's Copyright and Related Rights and associated claims and causes +of action, whether now known or unknown (including existing as well as +future claims and causes of action), in the Work (i) in all territories +worldwide, (ii) for the maximum duration provided by applicable law or +treaty (including future time extensions), (iii) in any current or future +medium and for any number of copies, and (iv) for any purpose whatsoever, +including without limitation commercial, advertising or promotional +purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each +member of the public at large and to the detriment of Affirmer's heirs and +successors, fully intending that such Waiver shall not be subject to +revocation, rescission, cancellation, termination, or any other legal or +equitable action to disrupt the quiet enjoyment of the Work by the public +as contemplated by Affirmer's express Statement of Purpose. + +3. Public License Fallback. Should any part of the Waiver for any reason +be judged legally invalid or ineffective under applicable law, then the +Waiver shall be preserved to the maximum extent permitted taking into +account Affirmer's express Statement of Purpose. In addition, to the +extent the Waiver is so judged Affirmer hereby grants to each affected +person a royalty-free, non transferable, non sublicensable, non exclusive, +irrevocable and unconditional license to exercise Affirmer's Copyright and +Related Rights in the Work (i) in all territories worldwide, (ii) for the +maximum duration provided by applicable law or treaty (including future +time extensions), (iii) in any current or future medium and for any number +of copies, and (iv) for any purpose whatsoever, including without +limitation commercial, advertising or promotional purposes (the +"License"). The License shall be deemed effective as of the date CC0 was +applied by Affirmer to the Work. Should any part of the License for any +reason be judged legally invalid or ineffective under applicable law, such +partial invalidity or ineffectiveness shall not invalidate the remainder +of the License, and in such case Affirmer hereby affirms that he or she +will not (i) exercise any of his or her remaining Copyright and Related +Rights in the Work or (ii) assert any associated claims and causes of +action with respect to the Work, in either case contrary to Affirmer's +express Statement of Purpose. + +4. Limitations and Disclaimers. + + a. No trademark or patent rights held by Affirmer are waived, abandoned, + surrendered, licensed or otherwise affected by this document. + b. Affirmer offers the Work as-is and makes no representations or + warranties of any kind concerning the Work, express, implied, + statutory or otherwise, including without limitation warranties of + title, merchantability, fitness for a particular purpose, non + infringement, or the absence of latent or other defects, accuracy, or + the present or absence of errors, whether or not discoverable, all to + the greatest extent permissible under applicable law. + c. Affirmer disclaims responsibility for clearing rights of other persons + that may apply to the Work or any use thereof, including without + limitation any person's Copyright and Related Rights in the Work. + Further, Affirmer disclaims responsibility for obtaining any necessary + consents, permissions or other rights required for any use of the + Work. + d. Affirmer understands and acknowledges that Creative Commons is not a + party to this document and has no duty or obligation with respect to + this CC0 or use of the Work. diff --git a/vendored_parsers/tree-sitter-janet-simple/package.json b/vendored_parsers/tree-sitter-janet-simple/package.json index d07e223a9..88225cd65 100644 --- a/vendored_parsers/tree-sitter-janet-simple/package.json +++ b/vendored_parsers/tree-sitter-janet-simple/package.json @@ -9,7 +9,7 @@ "install": "npx tree-sitter generate && npx node-gyp configure && npx node-gyp rebuild" }, "author": "", - "license": "", + "license": "CC0-1.0", "dependencies": { "nan": "2.14.2" },