diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile deleted file mode 100644 index 99c9d97..0000000 --- a/.devcontainer/Dockerfile +++ /dev/null @@ -1,76 +0,0 @@ -# ===----------------------------------------------------------------------=== # -# Copyright (c) 2023, Modular Inc. All rights reserved. -# -# Licensed under the Apache License v2.0 with LLVM Exceptions: -# https://llvm.org/LICENSE.txt -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -# The Dockerfile is provided as reference. Please review the redistribution -# terms of the Mojo license in Section 1 (https://www.modular.com/legal/mojo) -# prior to distributing pre-built container images. -# ===----------------------------------------------------------------------=== # - -# Example command line: -# Use no-cache to force docker to rebuild layers of the image by downloading the SDK from the repos -# ./build-image.sh --auth-key -# - -FROM ubuntu:22.04 - -ARG DEFAULT_TZ=America/Los_Angeles -ENV DEFAULT_TZ=$DEFAULT_TZ - -RUN apt-get update \ - && DEBIAN_FRONTEND=noninteractive TZ=$DEFAULT_TZ apt-get install -y \ - tzdata \ - vim \ - nano \ - sudo \ - curl \ - wget \ - python3-pip \ - git && \ - rm -rf /var/lib/apt/lists/* - - -# Download the latest version of minicoda py3.8 for linux x86/x64. -# RUN curl -fsSL https://repo.anaconda.com/miniconda/$( wget -O - https://repo.anaconda.com/miniconda/ 2>/dev/null | grep -o 'Miniconda3-py38_[^"]*-Linux-x86_64.sh' | head -n 1) > /tmp/miniconda.sh \ -# && chmod +x /tmp/miniconda.sh \ -# && /tmp/miniconda.sh -b -p /opt/conda - -# RUN mkdir -p ~/miniconda3 \ -# && wget https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh -O ~/miniconda3/miniconda.sh \ -# && bash ~/miniconda3/miniconda.sh -b -u -p ~/miniconda3 \ -# && rm -rf ~/miniconda3/miniconda.sh - -# ENV PATH=~/miniconda3/bin/conda:$PATH -# RUN conda init - -RUN pip install \ - pytest \ - git+https://github.com/guidorice/mojo-pytest.git - -# RUN pip install \ -# jupyterlab \ -# ipykernel \ -# matplotlib \ -# ipywidgets - -RUN curl https://get.modular.com | sh - -# RUN modular auth examples && modular install nightly/mojo -RUN modular auth examples && modular install mojo - -ARG MODULAR_HOME="/root/.modular" -ENV MODULAR_HOME=$MODULAR_HOME -# ENV PATH="$PATH:$MODULAR_HOME/pkg/packages.modular.com_nightly_mojo/bin" -ENV PATH="$PATH:$MODULAR_HOME/pkg/packages.modular.com_mojo/bin" - -# Change permissions to allow for Apptainer/Singularity containers -RUN chmod -R a+rwX /root - -# CMD ["jupyter", "lab", "--ip='*'", "--NotebookApp.token=''", "--NotebookApp.password=''","--allow-root"] diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json deleted file mode 100644 index 4ef9288..0000000 --- a/.devcontainer/devcontainer.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "name": "Mojo", - "build": { - "dockerfile": "Dockerfile" - }, - "customizations": { - // Configure properties specific to VS Code. - "vscode": { - // Set *default* container specific settings.json values on container create. - "settings": {}, - "extensions": [ - "modular-mojotools.vscode-mojo", - // "ms-toolsai.jupyter" - // "modular-mojotools.vscode-mojo-nightly" - ] - } - } -} diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..571ed81 --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,51 @@ +name: Build all packages + +on: + push: + branches: + - main + +# on: ["push"] + +jobs: + build: + strategy: + matrix: + include: + - { target: linux-64, os: ubuntu-latest } + - { target: osx-arm64, os: macos-14 } + fail-fast: false + + runs-on: ${{ matrix.os }} + timeout-minutes: 5 + + defaults: + run: + shell: bash + + steps: + - name: Checkout repo + uses: actions/checkout@v4 + + - name: Install magic + run: | + curl -ssL https://magic.modular.com | bash + + - name: Build package for target platform + env: + TARGET_PLATFORM: ${{ matrix.target }} + PREFIX_API_KEY: ${{ secrets.PREFIX_API_KEY }} + CONDA_BLD_PATH: ${{ runner.workspace }}/.rattler + + run: | + source $HOME/.bash_profile + + # Temporary method to fetch the rattler binary. + RATTLER_BINARY="rattler-build-aarch64-apple-darwin" + if [[ $TARGET_PLATFORM == "linux-64" ]]; then RATTLER_BINARY="rattler-build-x86_64-unknown-linux-musl"; fi + curl -SL --progress-bar https://github.com/prefix-dev/rattler-build/releases/latest/download/${RATTLER_BINARY} -o rattler-build + chmod +x rattler-build + + # Build and push + magic run build --target-platform=$TARGET_PLATFORM + magic run publish diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index d141180..654887c 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -2,25 +2,38 @@ name: Run Tests on: pull_request: + types: [opened, synchronize, reopened, ready_for_review] + +permissions: + contents: read + pull-requests: read jobs: test: - runs-on: ubuntu-latest - environment: basic + name: with ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + os: ["ubuntu-latest", "macos-14"] + + runs-on: ${{ matrix.os }} + timeout-minutes: 5 + + defaults: + run: + shell: bash + steps: - - name: Check out repository code - uses: actions/checkout@v2 - - name: Install dependencies + - name: Checkout repo + uses: actions/checkout@v4 + + - name: Install magic run: | - curl https://get.modular.com | MODULAR_AUTH=${{ secrets.MODULAR_AUTH }} sh - - modular auth ${{ secrets.MODULAR_AUTH }} - modular install mojo - pip install pytest - pip install git+https://github.com/guidorice/mojo-pytest.git - - name: Unit Tests + curl -ssL https://magic.modular.com | bash + + - name: Run tests run: | - export MODULAR_HOME="/home/runner/.modular" - export PATH="/home/runner/.modular/pkg/packages.modular.com_mojo/bin:$PATH" - pytest tests/unit - pytest tests/integration - bash run_examples.sh + source $HOME/.bash_profile + magic run tests + magic run benchmarks + magic run examples diff --git a/.gitignore b/.gitignore index 6769e21..e766feb 100644 --- a/.gitignore +++ b/.gitignore @@ -157,4 +157,20 @@ cython_debug/ # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore # and can be added to the global gitignore or merged into this file. For a more nuclear # option (not recommended) you can uncomment the following to ignore the entire idea folder. -#.idea/ \ No newline at end of file +#.idea/ + +# pixi environments +.pixi +*.egg-info + +# magic environments +.magic + +# Rattler +output + +# VSCode +.vscode/ + +# Mojo +*.mojopkg \ No newline at end of file diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 310b24b..5d8d8c1 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -9,7 +9,7 @@ repos: hooks: - id: mojo-format name: mojo-format - entry: mojo format -l 120 + entry: magic run mojo format -l 120 language: system files: '\.(mojo|🔥)$' stages: [commit] diff --git a/README.md b/README.md index 6b48f10..575f632 100644 --- a/README.md +++ b/README.md @@ -9,11 +9,13 @@ If you're a Go developer, please check out their CLI tooling and libraries. They For bugs and todos, see the bottom of the readme. At the moment, characters with a printable length greater than 1 ARE NOT supported. -You should be able to build the package by running `mojo package mog -I external`. For the easiest usage method, I recommend just copying the entire external folder into your repository, then copy the `mog` folder into the external folder as well. +## Installation -> NOTE: It seems like `.mojopkg` files don't like being part of another package, eg. sticking all of your external deps in an `external` or `vendor` package. The only way I've gotten mojopkg files to work is to be in the same directory as the file being executed, and that directory cannot be a mojo package. +1. First, you'll need to configure your `mojoproject.toml` file to include my Conda channel. Add `"https://repo.prefix.dev/mojo-community"` to the list of channels. +2. Next, add `mog` to your project's dependencies by running `magic add mog`. +3. Finally, run `magic install` to install in `mog` and its dependencies. You should see the `.mojopkg` files in `$CONDA_PREFIX/lib/mojo/`. -![Mog example](https://github.com/thatstoasty/mog/blob/main/demos/tapes/layout.gif) +![Mog example](https://github.com/thatstoasty/mog/blob/main/doc/tapes/layout.gif) Mog takes an expressive, declarative approach to terminal rendering. Users familiar with CSS will feel at home with Mog. @@ -408,7 +410,7 @@ print(t) Here's an example table rendering! -![Mog example](https://github.com/thatstoasty/mog/blob/main/demos/tapes/pokemon.gif) +![Mog example](https://github.com/thatstoasty/mog/blob/main/doc/tapes/pokemon.gif) --- diff --git a/benchmarks/__init__.mojo b/benchmarks/functions/__init__.mojo similarity index 100% rename from benchmarks/__init__.mojo rename to benchmarks/functions/__init__.mojo diff --git a/benchmarks/basic_styling.mojo b/benchmarks/functions/basic_styling.mojo similarity index 89% rename from benchmarks/basic_styling.mojo rename to benchmarks/functions/basic_styling.mojo index 5dc8676..ee49a87 100644 --- a/benchmarks/basic_styling.mojo +++ b/benchmarks/functions/basic_styling.mojo @@ -14,11 +14,11 @@ fn basic_styling(): ) var output = style.render("Hello, kitty") - keep(output) + _ = output -var file_style = ( - mog.Style() +alias file_style = ( + mog.Style(color_profile=mog.TRUE_COLOR) .bold(True) .foreground(mog.Color(0xFAFAFA)) .background(mog.Color(0x7D56F4)) @@ -30,7 +30,7 @@ var file_style = ( fn basic_comptime_styling(): var output = file_style.render("Hello, kitty") - keep(output) + _ = output fn basic_styling_big_file(): @@ -42,6 +42,6 @@ fn basic_styling_big_file(): 100 ) var output = style.render(content) - keep(output) + _ = output except e: print(e) diff --git a/benchmarks/layout.mojo b/benchmarks/functions/layout.mojo similarity index 98% rename from benchmarks/layout.mojo rename to benchmarks/functions/layout.mojo index 29ad970..642fd3f 100644 --- a/benchmarks/layout.mojo +++ b/benchmarks/functions/layout.mojo @@ -1,6 +1,6 @@ from benchmark.compiler import keep -from external.gojo.strings import StringBuilder -from external.weave.ansi import printable_rune_width +from gojo.strings import StringBuilder +from weave.ansi import printable_rune_width import mog from mog.join import join_vertical, join_horizontal from mog.border import HIDDEN_BORDER, NORMAL_BORDER, ROUNDED_BORDER, Border @@ -240,5 +240,5 @@ fn render_layout(): # Status bar _ = builder.write_string(build_status_bar()) - var output = doc_style.render(builder.render()) - keep(output) + var output = doc_style.render(str(builder)) + _ = output diff --git a/benchmarks/run.mojo b/benchmarks/run.mojo index b75f5fb..bdd6794 100644 --- a/benchmarks/run.mojo +++ b/benchmarks/run.mojo @@ -1,6 +1,6 @@ import benchmark -from benchmarks.layout import render_layout -from benchmarks.basic_styling import ( +from functions.layout import render_layout +from functions.basic_styling import ( basic_styling, basic_styling_big_file, basic_comptime_styling, @@ -8,8 +8,8 @@ from benchmarks.basic_styling import ( import mog -var style = mog.Style().alignment(mog.center, mog.center).padding(0, 1) -var header_style = style.foreground(mog.Color(0x39E506)) +alias style = mog.Style(color_profile=mog.TRUE_COLOR).alignment(mog.center, mog.center).padding(0, 1) +alias header_style = style.foreground(mog.Color(0x39E506)) fn table_styling(row: Int, col: Int) -> mog.Style: @@ -62,7 +62,7 @@ fn main(): ) # var bs_big_report = benchmark.run[basic_styling_big_file](max_iters=10) - # results.row( + # results = results.row( # "Large file test", # str(bs_big_report.mean(benchmark.Unit.ms)), # str(bs_big_report.duration(benchmark.Unit.ms)), diff --git a/demos/tapes/layout.gif b/doc/tapes/layout.gif similarity index 100% rename from demos/tapes/layout.gif rename to doc/tapes/layout.gif diff --git a/demos/tapes/layout.tape b/doc/tapes/layout.tape similarity index 100% rename from demos/tapes/layout.tape rename to doc/tapes/layout.tape diff --git a/demos/tapes/pokemon.gif b/doc/tapes/pokemon.gif similarity index 100% rename from demos/tapes/pokemon.gif rename to doc/tapes/pokemon.gif diff --git a/demos/tapes/pokemon.tape b/doc/tapes/pokemon.tape similarity index 100% rename from demos/tapes/pokemon.tape rename to doc/tapes/pokemon.tape diff --git a/examples/__init__.mojo b/examples/__init__.mojo deleted file mode 100644 index e69de29..0000000 diff --git a/examples/table/ansi.mojo b/examples/ansi.mojo similarity index 100% rename from examples/table/ansi.mojo rename to examples/ansi.mojo diff --git a/examples/readme/basic.mojo b/examples/basic.mojo similarity index 100% rename from examples/readme/basic.mojo rename to examples/basic.mojo diff --git a/examples/readme/layout.mojo b/examples/layout.mojo similarity index 90% rename from examples/readme/layout.mojo rename to examples/layout.mojo index a5ee257..8cdffb5 100644 --- a/examples/readme/layout.mojo +++ b/examples/layout.mojo @@ -1,5 +1,5 @@ -from external.gojo.strings import StringBuilder -from external.weave.ansi import printable_rune_width +from gojo.strings import StringBuilder +from weave.ansi import printable_rune_width from mog.join import join_vertical, join_horizontal from mog.border import HIDDEN_BORDER, NORMAL_BORDER, ROUNDED_BORDER, Border from mog.style import Style @@ -94,7 +94,6 @@ fn build_dialog_box() -> String: var buttons = join_horizontal(position.top, ok_button, cancel_button) var ui = join_vertical(position.center, question, buttons) - # TODO: Cannot handle unicode characters with a length greater than 1. For example: east asian characters like Kanji. return place( width, 9, @@ -116,9 +115,7 @@ fn build_lists() -> String: ).margin_right(2) var list_item = mog.Style().padding_left(2) - var check_mark = mog.Style().foreground(special).padding_right(1).render("✔") - var list_done = mog.Style().crossout().foreground(mog.AdaptiveColor(light=0x969B86, dark=0x696969)) var lists = join_horizontal( @@ -166,9 +163,9 @@ fn build_history() -> String: position.left ).foreground(mog.Color(0xFFFDF5)).background(highlight) - alias history_a = "The Romans learned from the Greeks that quinces slowly cooked with honey would “set” when cool. The Apicius gives a recipe for preserving whole quinces, stems and leaves attached, in a bath of honey diluted with defrutum: Roman marmalade. Preserves of quince and lemon appear (along with rose, apple, plum and pear) in the Book of ceremonies of the Byzantine Emperor Constantine VII Porphyrogennetos." + alias history_a = "The Romans learned from the Greeks that quinces slowly cooked with honey would 'set' when cool. The Apicius gives a recipe for preserving whole quinces, stems and leaves attached, in a bath of honey diluted with defrutum: Roman marmalade. Preserves of quince and lemon appear (along with rose, apple, plum and pear) in the Book of ceremonies of the Byzantine Emperor Constantine VII Porphyrogennetos." alias history_b = "Medieval quince preserves, which went by the French name cotignac, produced in a clear version and a fruit pulp version, began to lose their medieval seasoning of spices in the 16th century. In the 17th century, La Varenne provided recipes for both thick and clear cotignac." - alias history_c = "In 1524, Henry VIII, King of England, received a “box of marmalade” from Mr. Hull of Exeter. This was probably marmelada, a solid quince paste from Portugal, still made and sold in southern Europe today. It became a favourite treat of Anne Boleyn and her ladies in waiting." + alias history_c = "In 1524, Henry VIII, King of England, received a 'box of marmalade' from Mr. Hull of Exeter. This was probably marmelada, a solid quince paste from Portugal, still made and sold in southern Europe today. It became a favourite treat of Anne Boleyn and her ladies in waiting." return join_horizontal( position.top, @@ -180,14 +177,11 @@ fn build_history() -> String: fn build_status_bar() -> String: var status_nugget_style = mog.Style().foreground(mog.Color(0xFFFDF5)).padding(0, 1) - var status_bar_style = mog.Style().foreground(mog.Color(0xC1C6B2)).background(mog.Color(0x353533)) - var status_style = mog.Style().foreground(mog.Color(0xFFFDF5)).background(mog.Color(0xFF5F87)).padding(0, 1) # .margin_right(1) var encoding_style = status_nugget_style.background(mog.Color(0xA550DF)).horizontal_alignment(position.right) - var status_text_style = status_bar_style.padding_left(1) var fish_cake_style = status_nugget_style.background(mog.Color(0x6124DF)) @@ -238,4 +232,4 @@ fn main(): _ = builder.write_string(build_status_bar()) # Render the final document with doc_style - print(doc_style.render(builder.render())) + print(doc_style.render(str(builder))) diff --git a/examples/table/pokemon.mojo b/examples/pokemon.mojo similarity index 91% rename from examples/table/pokemon.mojo rename to examples/pokemon.mojo index cdaa13c..200dd6d 100644 --- a/examples/table/pokemon.mojo +++ b/examples/pokemon.mojo @@ -1,12 +1,14 @@ import mog +from collections import Dict # TODO: There's an issue with rows being taller than 1 line. Adding vertical padding will break the table. -var style = mog.Style().padding(0, 1) -var header_style = style.bold().foreground(mog.Color(252)) -var selected_style = style.foreground(mog.Color(0x01BE85)).background(mog.Color(0x00432F)) +# BUG: Mojo can't handle list of lists and dicts as aliases atm. +alias style = mog.Style(color_profile=mog.TRUE_COLOR).padding(0, 1) +alias header_style = style.bold().foreground(mog.Color(252)) +alias selected_style = style.foreground(mog.Color(0x01BE85)).background(mog.Color(0x00432F)) -var headers = List[String]("#", "Name", "Type 1", "Type 2", "Japanese", "Official Rom.") +alias headers = List[String]("#", "Name", "Type 1", "Type 2", "Japanese", "Official Rom.") var data = List[List[String]]( List[String]("1", "Bulbasaur", "Grass", "Poison", "フシギダネ", "Bulbasaur"), List[String]("2", "Ivysaur", "Grass", "Poison", "フシギソウ", "Ivysaur"), diff --git a/examples/readme/__init__.mojo b/examples/readme/__init__.mojo deleted file mode 100644 index e69de29..0000000 diff --git a/examples/table/__init__.mojo b/examples/table/__init__.mojo deleted file mode 100644 index e69de29..0000000 diff --git a/external/__init__.mojo b/external/__init__.mojo deleted file mode 100644 index e69de29..0000000 diff --git a/external/gojo/__init__.mojo b/external/gojo/__init__.mojo deleted file mode 100644 index e69de29..0000000 diff --git a/external/gojo/builtins/__init__.mojo b/external/gojo/builtins/__init__.mojo deleted file mode 100644 index 0827829..0000000 --- a/external/gojo/builtins/__init__.mojo +++ /dev/null @@ -1,5 +0,0 @@ -from .bytes import Byte, index_byte, has_suffix, has_prefix, to_string -from .attributes import cap, copy -from .errors import exit, panic - -alias Rune = Int32 diff --git a/external/gojo/builtins/attributes.mojo b/external/gojo/builtins/attributes.mojo deleted file mode 100644 index 7ce0b15..0000000 --- a/external/gojo/builtins/attributes.mojo +++ /dev/null @@ -1,141 +0,0 @@ -from collections import InlineList - - -fn copy[T: CollectionElement](inout target: List[T], source: List[T], start: Int = 0) -> Int: - """Copies the contents of source into target at the same index. Returns the number of bytes copied. - Added a start parameter to specify the index to start copying into. - - Args: - target: The buffer to copy into. - source: The buffer to copy from. - start: The index to start copying into. - - Returns: - The number of bytes copied. - """ - var count = 0 - - for i in range(len(source)): - if i + start > len(target): - target[i + start] = source[i] - else: - target.append(source[i]) - count += 1 - - return count - - -fn copy[T: CollectionElement](inout target_span: Span[T, True], source_span: Span[T], start: Int = 0) -> Int: - """Copies the contents of source into target at the same index. Returns the number of bytes copied. - Added a start parameter to specify the index to start copying into. - - Args: - target_span: The buffer to copy into. - source_span: The buffer to copy from. - start: The index to start copying into. - - Returns: - The number of bytes copied. - """ - var count = 0 - - for i in range(len(source_span)): - target_span[i + start] = source_span[i] - count += 1 - - target_span._len += count - return count - - -fn copy[T: CollectionElement](inout target_span: Span[T, True], source: InlineList[T], start: Int = 0) -> Int: - """Copies the contents of source into target at the same index. Returns the number of bytes copied. - Added a start parameter to specify the index to start copying into. - - Args: - target_span: The buffer to copy into. - source: The buffer to copy from. - start: The index to start copying into. - - Returns: - The number of bytes copied. - """ - var count = 0 - - for i in range(len(source)): - target_span[i + start] = source[i] - count += 1 - - target_span._len += count - return count - - -fn test(inout dest: List[UInt8]): - var source = List[UInt8](1, 2, 3) - var target = Span[UInt8](dest) - - _ = copy(target, Span(source), start=0) - - -fn copy[T: CollectionElement](inout list: InlineList[T], source: Span[T], start: Int = 0) -> Int: - """Copies the contents of source into target at the same index. Returns the number of bytes copied. - Added a start parameter to specify the index to start copying into. - - Args: - list: The buffer to copy into. - source: The buffer to copy from. - start: The index to start copying into. - - Returns: - The number of bytes copied. - """ - var count = 0 - - for i in range(len(source)): - if i + start > len(list): - list[i + start] = source[i] - else: - list.append(source[i]) - count += 1 - - return count - - -fn copy( - inout target: List[UInt8], - source: DTypePointer[DType.uint8], - source_start: Int, - source_end: Int, - target_start: Int = 0, -) -> Int: - """Copies the contents of source into target at the same index. Returns the number of bytes copied. - Added a start parameter to specify the index to start copying into. - - Args: - target: The buffer to copy into. - source: The buffer to copy from. - source_start: The index to start copying from. - source_end: The index to stop copying at. - target_start: The index to start copying into. - - Returns: - The number of bytes copied. - """ - var count = 0 - - for i in range(source_start, source_end): - if i + target_start > len(target): - target[i + target_start] = source[i] - else: - target.append(source[i]) - count += 1 - - return count - - -fn cap[T: CollectionElement](iterable: List[T]) -> Int: - """Returns the capacity of the List. - - Args: - iterable: The List to get the capacity of. - """ - return iterable.capacity diff --git a/external/gojo/builtins/bytes.mojo b/external/gojo/builtins/bytes.mojo deleted file mode 100644 index ff0dcb5..0000000 --- a/external/gojo/builtins/bytes.mojo +++ /dev/null @@ -1,107 +0,0 @@ -alias Byte = UInt8 - - -fn equals(left: List[UInt8], right: List[UInt8]) -> Bool: - if len(left) != len(right): - return False - for i in range(len(left)): - if left[i] != right[i]: - return False - return True - - -fn has_prefix(bytes: List[Byte], prefix: List[Byte]) -> Bool: - """Reports whether the List[Byte] struct begins with prefix. - - Args: - bytes: The List[Byte] struct to search. - prefix: The prefix to search for. - - Returns: - True if the List[Byte] struct begins with prefix; otherwise, False. - """ - var len_comparison = len(bytes) >= len(prefix) - var prefix_comparison = equals(bytes[0 : len(prefix)], prefix) - return len_comparison and prefix_comparison - - -fn has_suffix(bytes: List[Byte], suffix: List[Byte]) -> Bool: - """Reports whether the List[Byte] struct ends with suffix. - - Args: - bytes: The List[Byte] struct to search. - suffix: The prefix to search for. - - Returns: - True if the List[Byte] struct ends with suffix; otherwise, False. - """ - var len_comparison = len(bytes) >= len(suffix) - var suffix_comparison = equals(bytes[len(bytes) - len(suffix) : len(bytes)], suffix) - return len_comparison and suffix_comparison - - -fn index_byte(bytes: List[Byte], delim: Byte) -> Int: - """Return the index of the first occurrence of the byte delim. - - Args: - bytes: The List[Byte] struct to search. - delim: The byte to search for. - - Returns: - The index of the first occurrence of the byte delim. - """ - for i in range(len(bytes)): - if bytes[i] == delim: - return i - - return -1 - - -fn index_byte(bytes: DTypePointer[DType.uint8], size: Int, delim: Byte) -> Int: - """Return the index of the first occurrence of the byte delim. - - Args: - bytes: The DTypePointer[DType.int8] struct to search. - size: The size of the bytes pointer. - delim: The byte to search for. - - Returns: - The index of the first occurrence of the byte delim. - """ - for i in range(size): - if UInt8(bytes[i]) == delim: - return i - - return -1 - - -fn index_byte(bytes: Span[UInt8], delim: Byte) -> Int: - """Return the index of the first occurrence of the byte delim. - - Args: - bytes: The Span to search. - delim: The byte to search for. - - Returns: - The index of the first occurrence of the byte delim. - """ - for i in range(len(bytes)): - if bytes[i] == delim: - return i - - return -1 - - -fn to_string(bytes: List[Byte]) -> String: - """Makes a deepcopy of the List[Byte] supplied and converts it to a string. If it's not null terminated, it will append a null byte. - - Args: - bytes: The List[Byte] struct to convert. - - Returns: - The string representation of the List[Byte] struct. - """ - var copy = List[Byte](bytes) - if copy[-1] != 0: - copy.append(0) - return String(copy) diff --git a/external/gojo/builtins/errors.mojo b/external/gojo/builtins/errors.mojo deleted file mode 100644 index 1c1a7ba..0000000 --- a/external/gojo/builtins/errors.mojo +++ /dev/null @@ -1,12 +0,0 @@ -from sys import exit - - -fn panic[T: Stringable](message: T, code: Int = 1): - """Panics the program with the given message and exit code. - - Args: - message: The message to panic with. - code: The exit code to panic with. - """ - print("panic:", message) - exit(code) diff --git a/external/gojo/bytes/__init__.mojo b/external/gojo/bytes/__init__.mojo deleted file mode 100644 index 15170f2..0000000 --- a/external/gojo/bytes/__init__.mojo +++ /dev/null @@ -1,2 +0,0 @@ -from .buffer import Buffer, new_buffer -from .reader import Reader, new_reader diff --git a/external/gojo/bytes/buffer.mojo b/external/gojo/bytes/buffer.mojo deleted file mode 100644 index c5921ed..0000000 --- a/external/gojo/bytes/buffer.mojo +++ /dev/null @@ -1,518 +0,0 @@ -import ..io -from ..builtins import copy, Byte, panic, index_byte -from algorithm.memory import parallel_memcpy - - -alias Rune = Int32 - -# SMALL_BUFFER_SIZE is an initial allocation minimal capacity. -alias SMALL_BUFFER_SIZE: Int = 64 - -# The ReadOp constants describe the last action performed on -# the buffer, so that unread_rune and unread_byte can check for -# invalid usage. op_read_runeX constants are chosen such that -# converted to Int they correspond to the rune size that was read. -alias ReadOp = Int8 - -# Don't use iota for these, as the values need to correspond with the -# names and comments, which is easier to see when being explicit. -alias OP_READ: ReadOp = -1 # Any other read operation. -alias OP_INVALID: ReadOp = 0 # Non-read operation. -alias OP_READ_RUNE1: ReadOp = 1 # read rune of size 1. -alias OP_READ_RUNE2: ReadOp = 2 # read rune of size 2. -alias OP_READ_RUNE3: ReadOp = 3 # read rune of size 3. -alias OP_READ_RUNE4: ReadOp = 4 # read rune of size 4. - -alias MAX_INT: Int = 2147483647 -# MIN_READ is the minimum slice size passed to a read call by -# [Buffer.read_from]. As long as the [Buffer] has at least MIN_READ bytes beyond -# what is required to hold the contents of r, read_from will not grow the -# underlying buffer. -alias MIN_READ: Int = 512 - -# ERR_TOO_LARGE is passed to panic if memory cannot be allocated to store data in a buffer. -alias ERR_TOO_LARGE = "buffer.Buffer: too large" -alias ERR_NEGATIVE_READ = "buffer.Buffer: reader returned negative count from read" -alias ERR_SHORT_WRITE = "short write" - - -struct Buffer( - Stringable, - Sized, - io.Reader, - io.Writer, - io.StringWriter, - io.ByteWriter, - io.ByteReader, -): - var _data: UnsafePointer[UInt8] # contents are the bytes buf[off : len(buf)] - var _size: Int - var _capacity: Int - var offset: Int # read at &buf[off], write at &buf[len(buf)] - var last_read: ReadOp # last read operation, so that unread* can work correctly. - - @always_inline - fn __init__(inout self, capacity: Int = io.BUFFER_SIZE): - self._capacity = capacity - self._size = 0 - self._data = UnsafePointer[UInt8]().alloc(capacity) - self.offset = 0 - self.last_read = OP_INVALID - - @always_inline - fn __init__(inout self, owned buf: List[Byte]): - self._capacity = buf.capacity - self._size = buf.size - self._data = buf.steal_data() - self.offset = 0 - self.last_read = OP_INVALID - - @always_inline - fn __init__(inout self, owned data: UnsafePointer[UInt8], capacity: Int, size: Int): - self._capacity = capacity - self._size = size - self._data = data - self.offset = 0 - self.last_read = OP_INVALID - - @always_inline - fn __moveinit__(inout self, owned other: Self): - self._data = other._data - self._size = other._size - self._capacity = other._capacity - self.offset = other.offset - self.last_read = other.last_read - other._data = UnsafePointer[UInt8]() - other._size = 0 - other._capacity = 0 - other.offset = 0 - other.last_read = OP_INVALID - - @always_inline - fn __del__(owned self): - if self._data: - self._data.free() - - @always_inline - fn __len__(self) -> Int: - """Returns the number of bytes of the unread portion of the buffer. - self._size - self.offset.""" - return self._size - self.offset - - @always_inline - fn bytes_ptr(self) -> UnsafePointer[UInt8]: - """Returns a pointer holding the unread portion of the buffer.""" - return self._data.offset(self.offset) - - @always_inline - fn bytes(self) -> List[UInt8]: - """Returns a list of bytes holding a copy of the unread portion of the buffer.""" - var copy = UnsafePointer[UInt8]().alloc(self._size) - memcpy(copy, self._data.offset(self.offset), self._size) - return List[UInt8](unsafe_pointer=copy, size=self._size - self.offset, capacity=self._size - self.offset) - - @always_inline - fn as_bytes_slice(self: Reference[Self]) -> Span[UInt8, self.is_mutable, self.lifetime]: - """Returns the internal data as a Span[UInt8].""" - return Span[UInt8, self.is_mutable, self.lifetime](unsafe_ptr=self[]._data, len=self[]._size) - - @always_inline - fn _resize(inout self, capacity: Int) -> None: - """ - Resizes the string builder buffer. - - Args: - capacity: The new capacity of the string builder buffer. - """ - var new_data = UnsafePointer[UInt8]().alloc(capacity) - memcpy(new_data, self._data, self._size) - self._data.free() - self._data = new_data - self._capacity = capacity - - return None - - @always_inline - fn _resize_if_needed(inout self, bytes_to_add: Int): - # TODO: Handle the case where new_capacity is greater than MAX_INT. It should panic. - if bytes_to_add > self._capacity - self._size: - var new_capacity = int(self._capacity * 2) - if new_capacity < self._capacity + bytes_to_add: - new_capacity = self._capacity + bytes_to_add - self._resize(new_capacity) - - @always_inline - fn __str__(self) -> String: - """ - Converts the string builder to a string. - - Returns: - The string representation of the string builder. Returns an empty - string if the string builder is empty. - """ - var copy = UnsafePointer[UInt8]().alloc(self._size) - memcpy(copy, self._data, self._size) - return StringRef(copy, self._size) - - @always_inline - fn render(self: Reference[Self]) -> StringSlice[self.is_mutable, self.lifetime]: - """ - Return a StringSlice view of the data owned by the builder. - Slightly faster than __str__, 10-20% faster in limited testing. - - Returns: - The string representation of the string builder. Returns an empty string if the string builder is empty. - """ - return StringSlice[self.is_mutable, self.lifetime]( - unsafe_from_utf8_strref=StringRef(self[]._data, self[]._size) - ) - - @always_inline - fn _write(inout self, src: Span[Byte]) -> (Int, Error): - """ - Appends a byte Span to the builder buffer. - - Args: - src: The byte array to append. - """ - self._resize_if_needed(len(src)) - - memcpy(self._data.offset(self._size), src._data, len(src)) - self._size += len(src) - - return len(src), Error() - - @always_inline - fn write(inout self, src: List[Byte]) -> (Int, Error): - """ - Appends a byte List to the builder buffer. - - Args: - src: The byte array to append. - """ - var span = Span(src) - - var bytes_read: Int - var err: Error - bytes_read, err = self._write(span) - - return bytes_read, err - - @always_inline - fn write_string(inout self, src: String) -> (Int, Error): - """ - Appends a string to the builder buffer. - - Args: - src: The string to append. - """ - return self.write(src.as_bytes_slice()) - - @always_inline - fn write_byte(inout self, byte: Byte) -> (Int, Error): - """Appends the byte c to the buffer, growing the buffer as needed. - The returned error is always nil, but is included to match [bufio.Writer]'s - write_byte. If the buffer becomes too large, write_byte will panic with - [ERR_TOO_LARGE]. - - Args: - byte: The byte to write to the buffer. - - Returns: - The number of bytes written to the buffer. - """ - self.last_read = OP_INVALID - self._resize_if_needed(1) - self._data[self._size] = byte - self._size += 1 - - return 1, Error() - - @always_inline - fn empty(self) -> Bool: - """Reports whether the unread portion of the buffer is empty.""" - return self._size <= self.offset - - @always_inline - fn reset(inout self): - """Resets the buffer to be empty, - but it retains the underlying storage for use by future writes. - reset is the same as [buffer.truncate](0).""" - if self._data: - self._data.free() - self._data = UnsafePointer[UInt8]().alloc(self._capacity) - self._size = 0 - self.offset = 0 - self.last_read = OP_INVALID - - @always_inline - fn _read(inout self, inout dest: Span[Byte, True], capacity: Int) -> (Int, Error): - """Reads the next len(dest) bytes from the buffer or until the buffer - is drained. The return value n is the number of bytes read. If the - buffer has no data to return, err is io.EOF (unless len(dest) is zero); - otherwise it is nil. - - Args: - dest: The buffer to read into. - capacity: The capacity of the destination buffer. - - Returns: - The number of bytes read from the buffer. - """ - self.last_read = OP_INVALID - if self.empty(): - # Buffer is empty, reset to recover space. - self.reset() - # TODO: How to check if the span's pointer has 0 capacity? We want to return early if the span can't receive any data. - if capacity == 0: - return 0, Error() - return 0, io.EOF - - # Copy the data of the internal buffer from offset to len(buf) into the destination buffer at the given index. - var bytes_read = copy(dest, self.as_bytes_slice()[self.offset :]) - dest._len += bytes_read - self.offset += bytes_read - - if bytes_read > 0: - self.last_read = OP_READ - - return bytes_read, Error() - - @always_inline - fn read(inout self, inout dest: List[Byte]) -> (Int, Error): - """Reads the next len(dest) bytes from the buffer or until the buffer - is drained. The return value n is the number of bytes read. If the - buffer has no data to return, err is io.EOF (unless len(dest) is zero); - otherwise it is nil. - - Args: - dest: The buffer to read into. - - Returns: - The number of bytes read from the buffer. - """ - var span = Span(dest) - - var bytes_read: Int - var err: Error - bytes_read, err = self._read(span, dest.capacity) - dest.size += bytes_read - - return bytes_read, err - - @always_inline - fn read_byte(inout self) -> (Byte, Error): - """Reads and returns the next byte from the buffer. - If no byte is available, it returns error io.EOF. - """ - if self.empty(): - # Buffer is empty, reset to recover space. - self.reset() - return Byte(0), io.EOF - - var byte = self._data[self.offset] - self.offset += 1 - self.last_read = OP_READ - - return byte, Error() - - @always_inline - fn unread_byte(inout self) -> Error: - """Unreads the last byte returned by the most recent successful - read operation that read at least one byte. If a write has happened since - the last read, if the last read returned an error, or if the read read zero - bytes, unread_byte returns an error. - """ - if self.last_read == OP_INVALID: - return Error("buffer.Buffer: unread_byte: previous operation was not a successful read") - - self.last_read = OP_INVALID - if self.offset > 0: - self.offset -= 1 - - return Error() - - @always_inline - fn read_bytes(inout self, delim: Byte) -> (List[Byte], Error): - """Reads until the first occurrence of delim in the input, - returning a slice containing the data up to and including the delimiter. - If read_bytes encounters an error before finding a delimiter, - it returns the data read before the error and the error itself (often io.EOF). - read_bytes returns err != nil if and only if the returned data does not end in - delim. - - Args: - delim: The delimiter to read until. - - Returns: - A List[Byte] struct containing the data up to and including the delimiter. - """ - var slice: Span[UInt8, True, __lifetime_of(self)] - var err: Error - slice, err = self.read_slice(delim) - - var bytes = List[Byte](capacity=len(slice) + 1) - for byte in slice: - bytes.append(byte[]) - - return bytes, err - - @always_inline - fn read_slice(self: Reference[Self, True], delim: Byte) -> (Span[UInt8, self.is_mutable, self.lifetime], Error): - """Like read_bytes but returns a reference to internal buffer data. - - Args: - delim: The delimiter to read until. - - Returns: - A List[Byte] struct containing the data up to and including the delimiter. - """ - var i = index_byte(bytes=self[].as_bytes_slice(), delim=delim) - var end = self[].offset + i + 1 - - var err = Error() - if i < 0: - end = self[]._size - err = Error(str(io.EOF)) - - var line = self[].as_bytes_slice()[self[].offset : end] - self[].offset = end - self[].last_read = OP_READ - - return line, err - - @always_inline - fn read_string(inout self, delim: Byte) -> (String, Error): - """Reads until the first occurrence of delim in the input, - returning a string containing the data up to and including the delimiter. - If read_string encounters an error before finding a delimiter, - it returns the data read before the error and the error itself (often io.EOF). - read_string returns err != nil if and only if the returned data does not end - in delim. - - Args: - delim: The delimiter to read until. - - Returns: - A string containing the data up to and including the delimiter. - """ - var bytes: List[UInt8] - var err: Error - bytes, err = self.read_bytes(delim) - bytes.append(0) - - return String(bytes), err - - @always_inline - fn next(self: Reference[Self, True], number_of_bytes: Int) raises -> Span[Byte, self.is_mutable, self.lifetime]: - """Returns a slice containing the next n bytes from the buffer, - advancing the buffer as if the bytes had been returned by [Buffer.read]. - If there are fewer than n bytes in the buffer, next returns the entire buffer. - The slice is only valid until the next call to a read or write method. - - Args: - number_of_bytes: The number of bytes to read from the buffer. - - Returns: - A slice containing the next n bytes from the buffer. - """ - self[].last_read = OP_INVALID - var bytes_remaining = len(self[]) - var bytes_to_read = number_of_bytes - if bytes_to_read > bytes_remaining: - bytes_to_read = bytes_remaining - - var data = self[].as_bytes_slice()[self[].offset : self[].offset + bytes_to_read] - - self[].offset += bytes_to_read - if bytes_to_read > 0: - self[].last_read = OP_READ - - return data - - fn write_to[W: io.Writer](inout self, inout writer: W) -> (Int, Error): - """Writes data to w until the buffer is drained or an error occurs. - The return value n is the number of bytes written; Any error - encountered during the write is also returned. - - Args: - writer: The writer to write to. - - Returns: - The number of bytes written to the writer. - """ - self.last_read = OP_INVALID - var bytes_to_write = len(self) - var total_bytes_written: Int = 0 - - if bytes_to_write > 0: - var bytes_written: Int - var err: Error - bytes_written, err = writer.write(self.as_bytes_slice()[self.offset :]) - if bytes_written > bytes_to_write: - panic("bytes.Buffer.write_to: invalid write count") - - self.offset += bytes_written - total_bytes_written = bytes_written - if err: - return total_bytes_written, err - - # all bytes should have been written, by definition of write method in io.Writer - if bytes_written != bytes_to_write: - return total_bytes_written, Error(ERR_SHORT_WRITE) - - # Buffer is now empty; reset. - self.reset() - return total_bytes_written, Error() - - -fn new_buffer(capacity: Int = io.BUFFER_SIZE) -> Buffer: - """Creates and initializes a new [Buffer] using buf as its` - initial contents. The new [Buffer] takes ownership of buf, and the - caller should not use buf after this call. new_buffer is intended to - prepare a [Buffer] to read existing data. It can also be used to set - the initial size of the internal buffer for writing. To do that, - buf should have the desired capacity but a length of zero. - - In most cases, new([Buffer]) (or just declaring a [Buffer] variable) is - sufficient to initialize a [Buffer]. - """ - var b = List[Byte](capacity=capacity) - return Buffer(b^) - - -fn new_buffer(owned buf: List[Byte]) -> Buffer: - """Creates and initializes a new [Buffer] using buf as its` - initial contents. The new [Buffer] takes ownership of buf, and the - caller should not use buf after this call. new_buffer is intended to - prepare a [Buffer] to read existing data. It can also be used to set - the initial size of the internal buffer for writing. To do that, - buf should have the desired capacity but a length of zero. - - In most cases, new([Buffer]) (or just declaring a [Buffer] variable) is - sufficient to initialize a [Buffer]. - - Args: - buf: The bytes to use as the initial contents of the buffer. - - Returns: - A new [Buffer] initialized with the provided bytes. - """ - return Buffer(buf^) - - -fn new_buffer(owned s: String) -> Buffer: - """Creates and initializes a new [Buffer] using string s as its - initial contents. It is intended to prepare a buffer to read an existing - string. - - In most cases, new([Buffer]) (or just declaring a [Buffer] variable) is - sufficient to initialize a [Buffer]. - - Args: - s: The string to use as the initial contents of the buffer. - - Returns: - A new [Buffer] initialized with the provided string. - """ - return Buffer(s.as_bytes()) diff --git a/external/gojo/bytes/reader.mojo b/external/gojo/bytes/reader.mojo deleted file mode 100644 index 8948b9a..0000000 --- a/external/gojo/bytes/reader.mojo +++ /dev/null @@ -1,294 +0,0 @@ -from ..builtins import copy, panic -import ..io - - -# TODO: Maybe try a non owning reader, but I'm concerned about the lifetime of the buffer. -# Is making it unsafe a good idea? The source data would need to be ensured to outlive the reader by the user. -struct Reader( - Sized, - io.Reader, - io.ReaderAt, - io.WriterTo, - io.Seeker, - io.ByteReader, - io.ByteScanner, -): - """A Reader implements the io.Reader, io.ReaderAt, io.WriterTo, io.Seeker, - io.ByteScanner, and io.RuneScanner Interfaces by reading from - a byte slice. - Unlike a [Buffer], a Reader is read-only and supports seeking. - The zero value for Reader operates like a Reader of an empty slice. - """ - - var data: UnsafePointer[UInt8] # contents are the bytes buf[index : size] - var size: Int - var capacity: Int - var index: Int # current reading index - var prev_rune: Int # index of previous rune; or < 0 - - @always_inline - fn __init__(inout self, owned buffer: List[UInt8]): - """Initializes a new [Reader.Reader] struct.""" - self.capacity = buffer.capacity - self.size = buffer.size - self.data = buffer.steal_data() - self.index = 0 - self.prev_rune = -1 - - @always_inline - fn __moveinit__(inout self, owned other: Reader): - """Initializes a new [Reader.Reader] struct by moving the data from another [Reader.Reader] struct.""" - self.capacity = other.capacity - self.size = other.size - self.data = other.data - self.index = other.index - self.prev_rune = other.prev_rune - - other.data = UnsafePointer[UInt8]() - other.size = 0 - other.capacity = 0 - other.index = 0 - other.prev_rune = -1 - - @always_inline - fn __len__(self) -> Int: - """len returns the number of bytes of the unread portion of the - slice.""" - return self.size - int(self.index) - - @always_inline - fn __del__(owned self): - if self.data: - self.data.free() - - @always_inline - fn as_bytes_slice(self: Reference[Self]) -> Span[UInt8, self.is_mutable, self.lifetime]: - """Returns the internal data as a Span[UInt8].""" - return Span[UInt8, self.is_mutable, self.lifetime](unsafe_ptr=self[].data, len=self[].size) - - @always_inline - fn _read(inout self, inout dest: Span[UInt8, True], capacity: Int) -> (Int, Error): - """Reads from the internal buffer into the dest List[UInt8] struct. - Implements the [io.Reader] Interface. - - Args: - dest: The destination Span[UInt8] struct to read into. - capacity: The capacity of the destination buffer. - - Returns: - Int: The number of bytes read into dest.""" - - if self.index >= self.size: - return 0, io.EOF - - # Copy the data of the internal buffer from offset to len(buf) into the destination buffer at the given index. - self.prev_rune = -1 - var bytes_written = copy(dest, self.as_bytes_slice()[self.index : self.size], len(dest)) - dest._len += bytes_written - self.index += bytes_written - - return bytes_written, Error() - - @always_inline - fn read(inout self, inout dest: List[UInt8]) -> (Int, Error): - """Reads from the internal buffer into the dest List[UInt8] struct. - Implements the [io.Reader] Interface. - - Args: - dest: The destination List[UInt8] struct to read into. - - Returns: - Int: The number of bytes read into dest.""" - var span = Span(dest) - - var bytes_read: Int - var err: Error - bytes_read, err = self._read(span, dest.capacity) - dest.size += bytes_read - - return bytes_read, err - - @always_inline - fn _read_at(self, inout dest: Span[UInt8, True], off: Int, capacity: Int) -> (Int, Error): - """Reads len(dest) bytes into dest beginning at byte offset off. - Implements the [io.ReaderAt] Interface. - - Args: - dest: The destination List[UInt8] struct to read into. - off: The offset to start reading from. - - Returns: - Int: The number of bytes read into dest. - """ - # cannot modify state - see io.ReaderAt - if off < 0: - return 0, Error("bytes.Reader.read_at: negative offset") - - if off >= Int(self.size): - return 0, io.EOF - - var unread_bytes = self.as_bytes_slice()[off : self.size] - var bytes_written = copy(dest, unread_bytes) - if bytes_written < len(dest): - return 0, io.EOF - - return bytes_written, Error() - - @always_inline - fn read_at(self, inout dest: List[UInt8], off: Int) -> (Int, Error): - """Reads len(dest) bytes into dest beginning at byte offset off. - Implements the [io.ReaderAt] Interface. - - Args: - dest: The destination List[UInt8] struct to read into. - off: The offset to start reading from. - - Returns: - Int: The number of bytes read into dest. - """ - var span = Span(dest) - - var bytes_read: Int - var err: Error - bytes_read, err = self._read_at(span, off, dest.capacity) - dest.size += bytes_read - - return bytes_read, err - - @always_inline - fn read_byte(inout self) -> (UInt8, Error): - """Reads and returns a single byte from the internal buffer. Implements the [io.ByteReader] Interface.""" - self.prev_rune = -1 - if self.index >= self.size: - return UInt8(0), io.EOF - - var byte = self.data[self.index] - self.index += 1 - return byte, Error() - - @always_inline - fn unread_byte(inout self) -> Error: - """Unreads the last byte read by moving the read position back by one. - Complements [Reader.read_byte] in implementing the [io.ByteScanner] Interface. - """ - if self.index <= 0: - return Error("bytes.Reader.unread_byte: at beginning of slice") - - self.prev_rune = -1 - self.index -= 1 - - return Error() - - # # read_rune implements the [io.RuneReader] Interface. - # fn read_rune(self) (ch rune, size Int, err error): - # if self.index >= Int(self.size): - # self.prev_rune = -1 - # return 0, 0, io.EOF - - # self.prev_rune = Int(self.index) - # if c := self.buffer[self.index]; c < utf8.RuneSelf: - # self.index+= 1 - # return rune(c), 1, nil - - # ch, size = utf8.DecodeRune(self.buffer[self.index:]) - # self.index += Int(size) - # return - - # # unread_rune complements [Reader.read_rune] in implementing the [io.RuneScanner] Interface. - # fn unread_rune(self) error: - # if self.index <= 0: - # return errors.New("bytes.Reader.unread_rune: at beginning of slice") - - # if self.prev_rune < 0: - # return errors.New("bytes.Reader.unread_rune: previous operation was not read_rune") - - # self.index = Int(self.prev_rune) - # self.prev_rune = -1 - # return nil - - @always_inline - fn seek(inout self, offset: Int, whence: Int) -> (Int, Error): - """Moves the read position to the specified offset from the specified whence. - - Args: - offset: The offset to move to. - whence: The reference point for offset. - - Returns: - The new position in which the next read will start from. - """ - self.prev_rune = -1 - var position: Int = 0 - - if whence == io.SEEK_START: - position = offset - elif whence == io.SEEK_CURRENT: - position = self.index + offset - elif whence == io.SEEK_END: - position = self.size + offset - else: - return Int(0), Error("bytes.Reader.seek: invalid whence") - - if position < 0: - return Int(0), Error("bytes.Reader.seek: negative position") - - self.index = position - return position, Error() - - @always_inline - fn write_to[W: io.Writer](inout self, inout writer: W) -> (Int, Error): - """Writes data to w until the buffer is drained or an error occurs. - implements the [io.WriterTo] Interface. - - Args: - writer: The writer to write to. - """ - self.prev_rune = -1 - if self.index >= self.size: - return 0, Error() - - var bytes = self.as_bytes_slice()[self.index : self.size] - var write_count: Int - var err: Error - write_count, err = writer.write(bytes) - if write_count > len(bytes): - panic("bytes.Reader.write_to: invalid Write count") - - self.index += write_count - if write_count != len(bytes): - return write_count, io.ERR_SHORT_WRITE - - return write_count, Error() - - @always_inline - fn reset(inout self, owned buffer: List[UInt8]): - """Resets the [Reader.Reader] to be reading from buffer. - - Args: - buffer: The new buffer to read from. - """ - self.capacity = buffer.capacity - self.size = buffer.size - self.data = buffer.steal_data() - self.index = 0 - self.prev_rune = -1 - - -fn new_reader(owned buffer: List[UInt8]) -> Reader: - """Returns a new [Reader.Reader] reading from b. - - Args: - buffer: The new buffer to read from. - - """ - return Reader(buffer) - - -fn new_reader(owned buffer: String) -> Reader: - """Returns a new [Reader.Reader] reading from b. - - Args: - buffer: The new buffer to read from. - - """ - return Reader(buffer.as_bytes()) diff --git a/external/gojo/fmt/__init__.mojo b/external/gojo/fmt/__init__.mojo deleted file mode 100644 index a4b04e3..0000000 --- a/external/gojo/fmt/__init__.mojo +++ /dev/null @@ -1 +0,0 @@ -from .fmt import sprintf, printf, sprintf_str diff --git a/external/gojo/fmt/fmt.mojo b/external/gojo/fmt/fmt.mojo deleted file mode 100644 index 6766715..0000000 --- a/external/gojo/fmt/fmt.mojo +++ /dev/null @@ -1,236 +0,0 @@ -"""Formatting options -General -%v the value in a default format - when printing structs, the plus flag (%+v) adds field names - -Boolean -%t the word true or false - -Integer -%d base 10 -%q a single-quoted character literal. -%x base 16, with lower-case letters for a-f -%X base 16, with upper-case letters for A-F - -Floating-point and complex constituents: -%f decimal point but no exponent, e.g. 123.456 - -String and slice of bytes (treated equivalently with these verbs): -%s the uninterpreted bytes of the string or slice -%q a double-quoted string - -TODO: -- Add support for more formatting options -- Switch to buffered writing to avoid multiple string concatenations -- Add support for width and precision formatting options -- Handle escaping for String's %q -""" - -from utils.variant import Variant -from math import floor -from ..builtins import Byte - -alias Args = Variant[String, Int, Float64, Bool, List[Byte]] - - -fn replace_first(s: String, old: String, new: String) -> String: - """Replace the first occurrence of a substring in a string. - - Args: - s: The original string. - old: The substring to be replaced. - new: The new substring. - - Returns: - The string with the first occurrence of the old substring replaced by the new one. - """ - # Find the first occurrence of the old substring - var index = s.find(old) - - # If the old substring is found, replace it - if index != -1: - return s[:index] + new + s[index + len(old) :] - - # If the old substring is not found, return the original string - return s - - -fn find_first_verb(s: String, verbs: List[String]) -> String: - """Find the first occurrence of a verb in a string. - - Args: - s: The original string. - verbs: The list of verbs to search for. - - Returns: - The verb to replace. - """ - var index = -1 - var verb: String = "" - - for v in verbs: - var i = s.find(v[]) - if i != -1 and (index == -1 or i < index): - index = i - verb = v[] - - return verb - - -alias BASE10_TO_BASE16 = List[String]( - "0", - "1", - "2", - "3", - "4", - "5", - "6", - "7", - "8", - "9", - "a", - "b", - "c", - "d", - "e", - "f", -) - - -fn convert_base10_to_base16(value: Int) -> String: - """Converts a base 10 number to base 16. - - Args: - value: Base 10 number. - - Returns: - Base 16 number as a String. - """ - - var val: Float64 = 0.0 - var result: Float64 = value - var base16: String = "" - while result > 1: - var temp = result / 16 - var floor_result = floor(temp) - var remainder = temp - floor_result - result = floor_result - val = 16 * remainder - - base16 = BASE10_TO_BASE16[int(val)] + base16 - - return base16 - - -fn format_string(format: String, arg: String) -> String: - var verb = find_first_verb(format, List[String]("%s", "%q")) - var arg_to_place = arg - if verb == "%q": - arg_to_place = '"' + arg + '"' - - return replace_first(format, String("%s"), arg) - - -fn format_bytes(format: String, arg: List[Byte]) -> String: - var argument = arg - if argument[-1] != 0: - argument.append(0) - - return format_string(format, argument) - - -fn format_integer(format: String, arg: Int) -> String: - var verb = find_first_verb(format, List[String]("%x", "%X", "%d", "%q")) - var arg_to_place = str(arg) - if verb == "%x": - arg_to_place = str(convert_base10_to_base16(arg)).lower() - elif verb == "%X": - arg_to_place = str(convert_base10_to_base16(arg)).upper() - elif verb == "%q": - arg_to_place = "'" + str(arg) + "'" - - return replace_first(format, verb, arg_to_place) - - -fn format_float(format: String, arg: Float64) -> String: - return replace_first(format, str("%f"), str(arg)) - - -fn format_boolean(format: String, arg: Bool) -> String: - var value: String = "False" - if arg: - value = "True" - - return replace_first(format, String("%t"), value) - - -# If the number of arguments does not match the number of format specifiers -alias BadArgCount = "(BAD ARG COUNT)" - - -fn sprintf(formatting: String, *args: Args) -> String: - var text = formatting - var raw_percent_count = formatting.count("%%") * 2 - var formatter_count = formatting.count("%") - raw_percent_count - - if formatter_count != len(args): - return BadArgCount - - for i in range(len(args)): - var argument = args[i] - if argument.isa[String](): - text = format_string(text, argument[String]) - elif argument.isa[List[Byte]](): - text = format_bytes(text, argument[List[Byte]]) - elif argument.isa[Int](): - text = format_integer(text, argument[Int]) - elif argument.isa[Float64](): - text = format_float(text, argument[Float64]) - elif argument.isa[Bool](): - text = format_boolean(text, argument[Bool]) - - return text - - -# TODO: temporary until we have arg packing. -fn sprintf_str(formatting: String, args: List[String]) raises -> String: - var text = formatting - var formatter_count = formatting.count("%") - - if formatter_count > len(args): - raise Error("Not enough arguments for format string") - elif formatter_count < len(args): - raise Error("Too many arguments for format string") - - for i in range(len(args)): - text = format_string(text, args[i]) - - return text - - -fn printf(formatting: String, *args: Args) raises: - var text = formatting - var raw_percent_count = formatting.count("%%") * 2 - var formatter_count = formatting.count("%") - raw_percent_count - - if formatter_count > len(args): - raise Error("Not enough arguments for format string") - elif formatter_count < len(args): - raise Error("Too many arguments for format string") - - for i in range(len(args)): - var argument = args[i] - if argument.isa[String](): - text = format_string(text, argument[String]) - elif argument.isa[List[Byte]](): - text = format_bytes(text, argument[List[Byte]]) - elif argument.isa[Int](): - text = format_integer(text, argument[Int]) - elif argument.isa[Float64](): - text = format_float(text, argument[Float64]) - elif argument.isa[Bool](): - text = format_boolean(text, argument[Bool]) - else: - raise Error("Unknown for argument #" + str(i)) - - print(text) diff --git a/external/gojo/io/__init__.mojo b/external/gojo/io/__init__.mojo deleted file mode 100644 index fb4e9b6..0000000 --- a/external/gojo/io/__init__.mojo +++ /dev/null @@ -1,334 +0,0 @@ -from .io import write_string, read_at_least, read_full, read_all, BUFFER_SIZE -from .file import FileWrapper -from .std import STDWriter - - -alias Rune = Int32 - -# Package io provides basic interfaces to I/O primitives. -# Its primary job is to wrap existing implementations of such primitives, -# such as those in package os, into shared public interfaces that -# abstract the fntionality, plus some other related primitives. -# -# Because these interfaces and primitives wrap lower-level operations with -# various implementations, unless otherwise informed clients should not -# assume they are safe for parallel execution. -# Seek whence values. -alias SEEK_START = 0 # seek relative to the origin of the file -alias SEEK_CURRENT = 1 # seek relative to the current offset -alias SEEK_END = 2 # seek relative to the end - -# ERR_SHORT_WRITE means that a write accepted fewer bytes than requested -# but failed to return an explicit error. -alias ERR_SHORT_WRITE = Error("short write") - -# ERR_INVALID_WRITE means that a write returned an impossible count. -alias ERR_INVALID_WRITE = Error("invalid write result") - -# ERR_SHORT_BUFFER means that a read required a longer buffer than was provided. -alias ERR_SHORT_BUFFER = Error("short buffer") - -# EOF is the error returned by Read when no more input is available. -# (Read must return EOF itself, not an error wrapping EOF, -# because callers will test for EOF using ==.) -# fntions should return EOF only to signal a graceful end of input. -# If the EOF occurs unexpectedly in a structured data stream, -# the appropriate error is either [ERR_UNEXPECTED_EOF] or some other error -# giving more detail. -alias EOF = Error("EOF") - -# ERR_UNEXPECTED_EOF means that EOF was encountered in the -# middle of reading a fixed-size block or data structure. -alias ERR_UNEXPECTED_EOF = Error("unexpected EOF") - -# ERR_NO_PROGRESS is returned by some clients of a [Reader] when -# many calls to Read have failed to return any data or error, -# usually the sign of a broken [Reader] implementation. -alias ERR_NO_PROGRESS = Error("multiple Read calls return no data or error") - - -trait Reader(Movable): - """Reader is the trait that wraps the basic Read method. - - Read reads up to len(p) bytes into p. It returns the number of bytes - read (0 <= n <= len(p)) and any error encountered. Even if Read - returns n < len(p), it may use all of p as scratch space during the call. - If some data is available but not len(p) bytes, Read conventionally - returns what is available instead of waiting for more. - - When Read encounters an error or end-of-file condition after - successfully reading n > 0 bytes, it returns the number of - bytes read. It may return the (non-nil) error from the same call - or return the error (and n == 0) from a subsequent call. - An instance of this general case is that a Reader returning - a non-zero number of bytes at the end of the input stream may - return either err == EOF or err == nil. The next Read should - return 0, EOF. - - Callers should always process the n > 0 bytes returned before - considering the error err. Doing so correctly handles I/O errors - that happen after reading some bytes and also both of the - allowed EOF behaviors. - - If len(p) == 0, Read should always return n == 0. It may return a - non-nil error if some error condition is known, such as EOF. - - Implementations of Read are discouraged from returning a - zero byte count with a nil error, except when len(p) == 0. - Callers should treat a return of 0 and nil as indicating that - nothing happened; in particular it does not indicate EOF. - - Implementations must not retain p.""" - - fn read(inout self, inout dest: List[UInt8]) -> (Int, Error): - ... - - fn _read(inout self, inout dest: Span[UInt8, True], capacity: Int) -> (Int, Error): - ... - - -trait Writer(Movable): - """Writer is the trait that wraps the basic Write method. - - Write writes len(p) bytes from p to the underlying data stream. - It returns the number of bytes written from p (0 <= n <= len(p)) - and any error encountered that caused the write to stop early. - Write must return a non-nil error if it returns n < len(p). - Write must not modify the slice data, even temporarily. - - Implementations must not retain p. - """ - - # fn _write(inout self, src: Span[UInt8]) -> (Int, Error): - # ... - - fn write(inout self, src: List[UInt8]) -> (Int, Error): - ... - - -trait Closer(Movable): - """ - Closer is the trait that wraps the basic Close method. - - The behavior of Close after the first call is undefined. - Specific implementations may document their own behavior. - """ - - fn close(inout self) -> Error: - ... - - -trait Seeker(Movable): - """ - Seeker is the trait that wraps the basic Seek method. - - Seek sets the offset for the next Read or Write to offset, - interpreted according to whence: - [SEEK_START] means relative to the start of the file, - [SEEK_CURRENT] means relative to the current offset, and - [SEEK_END] means relative to the end - (for example, offset = -2 specifies the penultimate byte of the file). - Seek returns the new offset relative to the start of the - file or an error, if any. - - Seeking to an offset before the start of the file is an error. - Seeking to any positive offset may be allowed, but if the new offset exceeds - the size of the underlying object the behavior of subsequent I/O operations - is implementation-dependent. - """ - - fn seek(inout self, offset: Int, whence: Int) -> (Int, Error): - ... - - -trait ReadWriter(Reader, Writer): - ... - - -trait ReadCloser(Reader, Closer): - ... - - -trait WriteCloser(Writer, Closer): - ... - - -trait ReadWriteCloser(Reader, Writer, Closer): - ... - - -trait ReadSeeker(Reader, Seeker): - ... - - -trait ReadSeekCloser(Reader, Seeker, Closer): - ... - - -trait WriteSeeker(Writer, Seeker): - ... - - -trait ReadWriteSeeker(Reader, Writer, Seeker): - ... - - -trait ReaderFrom: - """ReaderFrom is the trait that wraps the ReadFrom method. - - ReadFrom reads data from r until EOF or error. - The return value n is the number of bytes read. - Any error except EOF encountered during the read is also returned. - - The [copy] function uses [ReaderFrom] if available.""" - - fn read_from[R: Reader](inout self, inout reader: R) -> (Int, Error): - ... - - -trait WriterReadFrom(Writer, ReaderFrom): - ... - - -trait WriterTo: - """WriterTo is the trait that wraps the WriteTo method. - - WriteTo writes data to w until there's no more data to write or - when an error occurs. The return value n is the number of bytes - written. Any error encountered during the write is also returned. - - The copy function uses WriterTo if available.""" - - fn write_to[W: Writer](inout self, inout writer: W) -> (Int, Error): - ... - - -trait ReaderWriteTo(Reader, WriterTo): - ... - - -trait ReaderAt: - """ReaderAt is the trait that wraps the basic ReadAt method. - - ReadAt reads len(p) bytes into p starting at offset off in the - underlying input source. It returns the number of bytes - read (0 <= n <= len(p)) and any error encountered. - - When ReadAt returns n < len(p), it returns a non-nil error - explaining why more bytes were not returned. In this respect, - ReadAt is stricter than Read. - - Even if ReadAt returns n < len(p), it may use all of p as scratch - space during the call. If some data is available but not len(p) bytes, - ReadAt blocks until either all the data is available or an error occurs. - In this respect ReadAt is different from Read. - - If the n = len(p) bytes returned by ReadAt are at the end of the - input source, ReadAt may return either err == EOF or err == nil. - - If ReadAt is reading from an input source with a seek offset, - ReadAt should not affect nor be affected by the underlying - seek offset. - - Clients of ReadAt can execute parallel ReadAt calls on the - same input source. - - Implementations must not retain p.""" - - fn read_at(self, inout dest: List[UInt8], off: Int) -> (Int, Error): - ... - - fn _read_at(self, inout dest: Span[UInt8, True], off: Int, capacity: Int) -> (Int, Error): - ... - - -trait WriterAt: - """WriterAt is the trait that wraps the basic WriteAt method. - - WriteAt writes len(p) bytes from p to the underlying data stream - at offset off. It returns the number of bytes written from p (0 <= n <= len(p)) - and any error encountered that caused the write to stop early. - WriteAt must return a non-nil error if it returns n < len(p). - - If WriteAt is writing to a destination with a seek offset, - WriteAt should not affect nor be affected by the underlying - seek offset. - - Clients of WriteAt can execute parallel WriteAt calls on the same - destination if the ranges do not overlap. - - Implementations must not retain p.""" - - fn _write_at(self, src: Span[UInt8], off: Int) -> (Int, Error): - ... - - fn write_at(self, src: List[UInt8], off: Int) -> (Int, Error): - ... - - -trait ByteReader: - """ByteReader is the trait that wraps the read_byte method. - - read_byte reads and returns the next byte from the input or - any error encountered. If read_byte returns an error, no input - byte was consumed, and the returned byte value is undefined. - - read_byte provides an efficient trait for byte-at-time - processing. A [Reader] that does not implement ByteReader - can be wrapped using bufio.NewReader to add this method.""" - - fn read_byte(inout self) -> (UInt8, Error): - ... - - -trait ByteScanner(ByteReader): - """ByteScanner is the trait that adds the unread_byte method to the - basic read_byte method. - - unread_byte causes the next call to read_byte to return the last byte read. - If the last operation was not a successful call to read_byte, unread_byte may - return an error, unread the last byte read (or the byte prior to the - last-unread byte), or (in implementations that support the [Seeker] trait) - seek to one byte before the current offset.""" - - fn unread_byte(inout self) -> Error: - ... - - -trait ByteWriter: - """ByteWriter is the trait that wraps the write_byte method.""" - - fn write_byte(inout self, byte: UInt8) -> (Int, Error): - ... - - -trait RuneReader: - """RuneReader is the trait that wraps the read_rune method. - - read_rune reads a single encoded Unicode character - and returns the rune and its size in bytes. If no character is - available, err will be set.""" - - fn read_rune(inout self) -> (Rune, Int): - ... - - -trait RuneScanner(RuneReader): - """RuneScanner is the trait that adds the unread_rune method to the - basic read_rune method. - - unread_rune causes the next call to read_rune to return the last rune read. - If the last operation was not a successful call to read_rune, unread_rune may - return an error, unread the last rune read (or the rune prior to the - last-unread rune), or (in implementations that support the [Seeker] trait) - seek to the start of the rune before the current offset.""" - - fn unread_rune(inout self) -> Rune: - ... - - -trait StringWriter: - """StringWriter is the trait that wraps the WriteString method.""" - - fn write_string(inout self, src: String) -> (Int, Error): - ... diff --git a/external/gojo/io/file.mojo b/external/gojo/io/file.mojo deleted file mode 100644 index 443ae93..0000000 --- a/external/gojo/io/file.mojo +++ /dev/null @@ -1,148 +0,0 @@ -import ..io -from ..builtins import copy -from ..syscall import FileDescriptorBase - - -struct FileWrapper(FileDescriptorBase, io.ByteReader): - var handle: FileHandle - - @always_inline - fn __init__(inout self, path: String, mode: String) raises: - self.handle = open(path, mode) - - @always_inline - fn __moveinit__(inout self, owned existing: Self): - self.handle = existing.handle^ - - @always_inline - fn __del__(owned self): - var err = self.close() - if err: - # TODO: __del__ can't raise, but there should be some fallback. - print(str(err)) - - @always_inline - fn close(inout self) -> Error: - try: - self.handle.close() - except e: - return e - - return Error() - - @always_inline - fn _read(inout self, inout dest: Span[UInt8, True], capacity: Int) -> (Int, Error): - """Read from the file handle into dest's pointer. - Pretty hacky way to force the filehandle read into the defined trait, and it's unsafe since we're - reading directly into the pointer. - """ - # var bytes_to_read = dest.capacity - len(dest) - var bytes_read: Int - var result: List[UInt8] - try: - result = self.handle.read_bytes() - bytes_read = len(result) - # TODO: Need to raise an Issue for this. Reading with pointer does not return an accurate count of bytes_read :( - # bytes_read = int(self.handle.read(DTypePointer[DType.uint8](dest.unsafe_ptr()) + dest.size)) - except e: - return 0, e - - _ = copy(dest, Span(result), len(dest)) - - if bytes_read == 0: - return bytes_read, io.EOF - - return bytes_read, Error() - - @always_inline - fn read(inout self, inout dest: List[UInt8]) -> (Int, Error): - """Read from the file handle into dest's pointer. - Pretty hacky way to force the filehandle read into the defined trait, and it's unsafe since we're - reading directly into the pointer. - """ - # var bytes_to_read = dest.capacity - len(dest) - var bytes_read: Int - var result: List[UInt8] - try: - result = self.handle.read_bytes() - bytes_read = len(result) - # TODO: Need to raise an Issue for this. Reading with pointer does not return an accurate count of bytes_read :( - # bytes_read = int(self.handle.read(DTypePointer[DType.uint8](dest.unsafe_ptr()) + dest.size)) - except e: - return 0, e - - _ = copy(dest, result, len(dest)) - - if bytes_read == 0: - return bytes_read, io.EOF - - return bytes_read, Error() - - @always_inline - fn read_all(inout self) -> (List[UInt8], Error): - var bytes = List[UInt8](capacity=io.BUFFER_SIZE) - while True: - var temp = List[UInt8](capacity=io.BUFFER_SIZE) - _ = self.read(temp) - - # If new bytes will overflow the result, resize it. - if len(bytes) + len(temp) > bytes.capacity: - bytes.reserve(bytes.capacity * 2) - bytes.extend(temp) - - if len(temp) < io.BUFFER_SIZE: - return bytes, io.EOF - - @always_inline - fn read_byte(inout self) -> (UInt8, Error): - try: - var bytes: List[UInt8] - var err: Error - bytes, err = self.read_bytes(1) - return bytes[0], Error() - except e: - return UInt8(0), e - - @always_inline - fn read_bytes(inout self, size: Int = -1) raises -> (List[UInt8], Error): - try: - return self.handle.read_bytes(size), Error() - except e: - return List[UInt8](), e - - @always_inline - fn stream_until_delimiter(inout self, inout dest: List[UInt8], delimiter: UInt8, max_size: Int) -> Error: - var byte: UInt8 - var err = Error() - for _ in range(max_size): - byte, err = self.read_byte() - if err: - return err - - if byte == delimiter: - return err - dest.append(byte) - return Error("Stream too long") - - @always_inline - fn seek(inout self, offset: Int, whence: Int = 0) -> (Int, Error): - try: - var position = self.handle.seek(UInt64(offset), whence) - return int(position), Error() - except e: - return 0, e - - @always_inline - fn _write(inout self, src: Span[UInt8]) -> (Int, Error): - if len(src) == 0: - return 0, Error("No data to write") - - try: - self.handle.write(src.unsafe_ptr()) - return len(src), io.EOF - except e: - return 0, Error(str(e)) - - @always_inline - fn write(inout self, src: List[UInt8]) -> (Int, Error): - return self._write(Span(src)) diff --git a/external/gojo/io/io.mojo b/external/gojo/io/io.mojo deleted file mode 100644 index 87b7da2..0000000 --- a/external/gojo/io/io.mojo +++ /dev/null @@ -1,440 +0,0 @@ -from ..builtins import copy, Byte, panic - -alias BUFFER_SIZE = 4096 - - -fn write_string[W: Writer](inout writer: W, string: String) -> (Int, Error): - """Writes the contents of the string s to w, which accepts a slice of bytes. - If w implements [StringWriter], [StringWriter.write_string] is invoked directly. - Otherwise, [Writer.write] is called exactly once. - - Args: - writer: The writer to write to. - string: The string to write. - - Returns: - The number of bytes written and an error, if any. - """ - return writer.write(string.as_bytes()) - - -fn write_string[W: StringWriter](inout writer: W, string: String) -> (Int, Error): - """Writes the contents of the string s to w, which accepts a slice of bytes. - If w implements [StringWriter], [StringWriter.write_string] is invoked directly. - Otherwise, [Writer.write] is called exactly once. - - Args: - writer: The writer to write to. - string: The string to write. - - Returns: - The number of bytes written and an error, if any.""" - return writer.write_string(string) - - -fn read_at_least[R: Reader](inout reader: R, inout dest: List[Byte], min: Int) -> (Int, Error): - """Reads from r into buf until it has read at least min bytes. - It returns the number of bytes copied and an error if fewer bytes were read. - The error is EOF only if no bytes were read. - If an EOF happens after reading fewer than min bytes, - read_at_least returns [ERR_UNEXPECTED_EOF]. - If min is greater than the length of buf, read_at_least returns [ERR_SHORT_BUFFER]. - On return, n >= min if and only if err == nil. - If r returns an error having read at least min bytes, the error is dropped. - - Args: - reader: The reader to read from. - dest: The buffer to read into. - min: The minimum number of bytes to read. - - Returns: - The number of bytes read.""" - var error = Error() - if len(dest) < min: - return 0, io.ERR_SHORT_BUFFER - - var total_bytes_read: Int = 0 - while total_bytes_read < min and not error: - var bytes_read: Int - bytes_read, error = reader.read(dest) - total_bytes_read += bytes_read - - if total_bytes_read >= min: - error = Error() - - elif total_bytes_read > 0 and str(error): - error = ERR_UNEXPECTED_EOF - - return total_bytes_read, error - - -fn read_full[R: Reader](inout reader: R, inout dest: List[Byte]) -> (Int, Error): - """Reads exactly len(buf) bytes from r into buf. - It returns the number of bytes copied and an error if fewer bytes were read. - The error is EOF only if no bytes were read. - If an EOF happens after reading some but not all the bytes, - read_full returns [ERR_UNEXPECTED_EOF]. - On return, n == len(buf) if and only if err == nil. - If r returns an error having read at least len(buf) bytes, the error is dropped. - """ - return read_at_least(reader, dest, len(dest)) - - -# fn copy_n[W: Writer, R: Reader](dst: W, src: R, n: Int) raises -> Int: -# """Copies n bytes (or until an error) from src to dst. -# It returns the number of bytes copied and the earliest -# error encountered while copying. -# On return, written == n if and only if err == nil. - -# If dst implements [ReaderFrom], the copy is implemented using it. -# """ -# var written = copy(dst, LimitReader(src, n)) -# if written == n: -# return n - -# if written < n: -# # src stopped early; must have been EOF. -# raise Error(ERR_UNEXPECTED_EOF) - -# return written - - -# fn copy[W: Writer, R: Reader](dst: W, src: R, n: Int) -> Int: -# """copy copies from src to dst until either EOF is reached -# on src or an error occurs. It returns the number of bytes -# copied and the first error encountered while copying, if any. - -# A successful copy returns err == nil, not err == EOF. -# Because copy is defined to read from src until EOF, it does -# not treat an EOF from Read as an error to be reported. - -# If src implements [WriterTo], -# the copy is implemented by calling src.WriteTo(dst). -# Otherwise, if dst implements [ReaderFrom], -# the copy is implemented by calling dst.ReadFrom(src). -# """ -# return copy_buffer(dst, src, nil) - -# # CopyBuffer is identical to copy except that it stages through the -# # provided buffer (if one is required) rather than allocating a -# # temporary one. If buf is nil, one is allocated; otherwise if it has -# # zero length, CopyBuffer panics. -# # -# # If either src implements [WriterTo] or dst implements [ReaderFrom], -# # buf will not be used to perform the copy. -# fn CopyBuffer(dst Writer, src Reader, buf bytes) (written Int, err error) { -# if buf != nil and len(buf) == 0 { -# panic("empty buffer in CopyBuffer") -# } -# return copy_buffer(dst, src, buf) -# } - - -# fn copy_buffer[W: Writer, R: Reader](dst: W, src: R, buf: Span[Byte]) raises -> Int: -# """Actual implementation of copy and CopyBuffer. -# if buf is nil, one is allocated. -# """ -# var nr: Int -# nr = src.read(buf) -# while True: -# if nr > 0: -# var nw: Int -# nw = dst.write(get_slice(buf, 0, nr)) -# if nw < 0 or nr < nw: -# nw = 0 - -# var written = Int(nw) -# if nr != nw: -# raise Error(ERR_SHORT_WRITE) - -# return written - - -# fn copy_buffer[W: Writer, R: ReaderWriteTo](dst: W, src: R, buf: Span[Byte]) -> Int: -# return src.write_to(dst) - - -# fn copy_buffer[W: WriterReadFrom, R: Reader](dst: W, src: R, buf: Span[Byte]) -> Int: -# return dst.read_from(src) - -# # LimitReader returns a Reader that reads from r -# # but stops with EOF after n bytes. -# # The underlying implementation is a *LimitedReader. -# fn LimitReader(r Reader, n Int) Reader { return &LimitedReader{r, n} } - -# # A LimitedReader reads from R but limits the amount of -# # data returned to just N bytes. Each call to Read -# # updates N to reflect the new amount remaining. -# # Read returns EOF when N <= 0 or when the underlying R returns EOF. -# struct LimitedReader(): -# var R: Reader # underlying reader -# N Int # max bytes remaining - -# fn (l *LimitedReader) Read(p bytes) (n Int, err error) { -# if l.N <= 0 { -# return 0, EOF -# } -# if Int(len(p)) > l.N { -# p = p[0:l.N] -# } -# n, err = l.R.Read(p) -# l.N -= Int(n) -# return -# } - -# # NewSectionReader returns a [SectionReader] that reads from r -# # starting at offset off and stops with EOF after n bytes. -# fn NewSectionReader(r ReaderAt, off Int, n Int) *SectionReader { -# var remaining Int -# const maxInt = 1<<63 - 1 -# if off <= maxInt-n { -# remaining = n + off -# } else { -# # Overflow, with no way to return error. -# # Assume we can read up to an offset of 1<<63 - 1. -# remaining = maxInt -# } -# return &SectionReader{r, off, off, remaining, n} -# } - -# # SectionReader implements Read, Seek, and ReadAt on a section -# # of an underlying [ReaderAt]. -# type SectionReader struct { -# r ReaderAt # constant after creation -# base Int # constant after creation -# off Int -# limit Int # constant after creation -# n Int # constant after creation -# } - -# fn (s *SectionReader) Read(p bytes) (n Int, err error) { -# if s.off >= s.limit { -# return 0, EOF -# } -# if max := s.limit - s.off; Int(len(p)) > max { -# p = p[0:max] -# } -# n, err = s.r.ReadAt(p, s.off) -# s.off += Int(n) -# return -# } - -# alias errWhence = "Seek: invalid whence" -# alias errOffset = "Seek: invalid offset" - -# fn (s *SectionReader) Seek(offset Int, whence Int) (Int, error) { -# switch whence { -# default: -# return 0, errWhence -# case SEEK_START: -# offset += s.base -# case SEEK_CURRENT: -# offset += s.off -# case SEEK_END: -# offset += s.limit -# } -# if offset < s.base { -# return 0, errOffset -# } -# s.off = offset -# return offset - s.base, nil -# } - -# fn (s *SectionReader) ReadAt(p bytes, off Int) (n Int, err error) { -# if off < 0 or off >= s.capacity { -# return 0, EOF -# } -# off += s.base -# if max := s.limit - off; Int(len(p)) > max { -# p = p[0:max] -# n, err = s.r.ReadAt(p, off) -# if err == nil { -# err = EOF -# } -# return n, err -# } -# return s.r.ReadAt(p, off) -# } - -# # Size returns the size of the section in bytes. -# fn (s *SectionReader) Size() Int { return s.limit - s.base } - -# # Outer returns the underlying [ReaderAt] and offsets for the section. -# # -# # The returned values are the same that were passed to [NewSectionReader] -# # when the [SectionReader] was created. -# fn (s *SectionReader) Outer() (r ReaderAt, off Int, n Int) { -# return s.r, s.base, s.n -# } - -# # An OffsetWriter maps writes at offset base to offset base+off in the underlying writer. -# type OffsetWriter struct { -# w WriterAt -# base Int # the original offset -# off Int # the current offset -# } - -# # NewOffsetWriter returns an [OffsetWriter] that writes to w -# # starting at offset off. -# fn NewOffsetWriter(w WriterAt, off Int) *OffsetWriter { -# return &OffsetWriter{w, off, off} -# } - -# fn (o *OffsetWriter) Write(p bytes) (n Int, err error) { -# n, err = o.w.WriteAt(p, o.off) -# o.off += Int(n) -# return -# } - -# fn (o *OffsetWriter) WriteAt(p bytes, off Int) (n Int, err error) { -# if off < 0 { -# return 0, errOffset -# } - -# off += o.base -# return o.w.WriteAt(p, off) -# } - -# fn (o *OffsetWriter) Seek(offset Int, whence Int) (Int, error) { -# switch whence { -# default: -# return 0, errWhence -# case SEEK_START: -# offset += o.base -# case SEEK_CURRENT: -# offset += o.off -# } -# if offset < o.base { -# return 0, errOffset -# } -# o.off = offset -# return offset - o.base, nil -# } - -# # TeeReader returns a [Reader] that writes to w what it reads from r. -# # All reads from r performed through it are matched with -# # corresponding writes to w. There is no internal buffering - -# # the write must complete before the read completes. -# # Any error encountered while writing is reported as a read error. -# fn TeeReader(r Reader, w Writer) Reader { -# return &teeReader{r, w} -# } - -# type teeReader struct { -# r Reader -# w Writer -# } - -# fn (t *teeReader) Read(p bytes) (n Int, err error) { -# n, err = t.r.Read(p) -# if n > 0 { -# if n, err := t.w.Write(p[:n]); err != nil { -# return n, err -# } -# } -# return -# } - -# # Discard is a [Writer] on which all Write calls succeed -# # without doing anything. -# var Discard Writer = discard{} - -# type discard struct{} - -# # discard implements ReaderFrom as an optimization so copy to -# # io.Discard can avoid doing unnecessary work. -# var _ ReaderFrom = discard{} - -# fn (discard) Write(p bytes) (Int, error) { -# return len(p), nil -# } - -# fn (discard) write_string(s string) (Int, error) { -# return len(s), nil -# } - -# var blackHolePool = sync.Pool{ -# New: fn() any { -# b := make(bytes, 8192) -# return &b -# }, -# } - -# fn (discard) ReadFrom(r Reader) (n Int, err error) { -# bufp := blackHolePool.Get().(*bytes) -# readSize := 0 -# for { -# readSize, err = r.Read(*bufp) -# n += Int(readSize) -# if err != nil { -# blackHolePool.Put(bufp) -# if err == EOF { -# return n, nil -# } -# return -# } -# } -# } - -# # NopCloser returns a [ReadCloser] with a no-op Close method wrapping -# # the provided [Reader] r. -# # If r implements [WriterTo], the returned [ReadCloser] will implement [WriterTo] -# # by forwarding calls to r. -# fn NopCloser(r Reader) ReadCloser { -# if _, ok := r.(WriterTo); ok { -# return nopCloserWriterTo{r} -# } -# return nopCloser{r} -# } - -# type nopCloser struct { -# Reader -# } - -# fn (nopCloser) Close() error { return nil } - -# type nopCloserWriterTo struct { -# Reader -# } - -# fn (nopCloserWriterTo) Close() error { return nil } - -# fn (c nopCloserWriterTo) WriteTo(w Writer) (n Int, err error) { -# return c.Reader.(WriterTo).WriteTo(w) -# } - - -# TODO: read directly into dest -fn read_all[R: Reader](inout reader: R) -> (List[Byte], Error): - """Reads from r until an error or EOF and returns the data it read. - A successful call returns err == nil, not err == EOF. Because ReadAll is - defined to read from src until EOF, it does not treat an EOF from Read - as an error to be reported. - - Args: - reader: The reader to read from. - - Returns: - The data read.""" - var dest = List[Byte](capacity=BUFFER_SIZE) - var at_eof: Bool = False - - while True: - var temp = List[Byte](capacity=BUFFER_SIZE) - var bytes_read: Int - var err: Error - bytes_read, err = reader.read(temp) - if str(err) != "": - if str(err) != str(EOF): - return dest, err - - at_eof = True - - # If new bytes will overflow the result, resize it. - # if some bytes were written, how do I append before returning result on the last one? - if len(dest) + len(temp) > dest.capacity: - dest.reserve(dest.capacity * 2) - dest.extend(temp) - - if at_eof: - return dest, err diff --git a/external/gojo/io/std.mojo b/external/gojo/io/std.mojo deleted file mode 100644 index 553be78..0000000 --- a/external/gojo/io/std.mojo +++ /dev/null @@ -1,71 +0,0 @@ -import ..io -from ..syscall import FD - - -@value -struct STDWriter[file_descriptor: Int](Copyable, io.Writer, io.StringWriter): - """A writer for POSIX file descriptors.""" - - @always_inline - fn __init__(inout self): - constrained[ - file_descriptor == FD.STDOUT or file_descriptor == FD.STDERR, - "The STDWriter Struct is meant to write to STDOUT and STDERR. file_descriptor must be 1 or 2.", - ]() - - @always_inline - fn _write(inout self, src: Span[UInt8]) -> (Int, Error): - """Writes the given bytes to the file descriptor. - - Args: - src: The bytes to write to the file descriptor. - - Returns: - The number of bytes written to the file descriptor. - """ - var write_count: Int = external_call["write", Int, Int32, UnsafePointer[UInt8], Int]( - file_descriptor, src.unsafe_ptr(), len(src) - ) - - if write_count == -1: - return 0, Error("Failed to write to file descriptor " + str(file_descriptor)) - - return write_count, Error() - - @always_inline - fn write(inout self, src: List[UInt8]) -> (Int, Error): - """Writes the given bytes to the file descriptor. - - Args: - src: The bytes to write to the file descriptor. - - Returns: - The number of bytes written to the file descriptor. - """ - return self._write(Span(src)) - - @always_inline - fn write_string(inout self, src: String) -> (Int, Error): - """Writes the given string to the file descriptor. - - Args: - src: The string to write to the file descriptor. - - Returns: - The number of bytes written to the file descriptor. - """ - return self._write(src.as_bytes_slice()) - - @always_inline - fn read_from[R: io.Reader](inout self, inout reader: R) -> (Int, Error): - """Reads from the given reader to a temporary buffer and writes to the file descriptor. - - Args: - reader: The reader to read from. - - Returns: - The number of bytes written to the file descriptor. - """ - var buffer = List[UInt8](capacity=io.BUFFER_SIZE) - _ = reader.read(buffer) - return self._write(Span(buffer)) diff --git a/external/gojo/strings/__init__.mojo b/external/gojo/strings/__init__.mojo deleted file mode 100644 index fbcb44e..0000000 --- a/external/gojo/strings/__init__.mojo +++ /dev/null @@ -1,2 +0,0 @@ -from .builder import StringBuilder -from .reader import Reader, new_reader diff --git a/external/gojo/strings/builder.mojo b/external/gojo/strings/builder.mojo deleted file mode 100644 index 24ac6cd..0000000 --- a/external/gojo/strings/builder.mojo +++ /dev/null @@ -1,167 +0,0 @@ -import ..io - - -struct StringBuilder[growth_factor: Float32 = 2]( - Stringable, - Sized, - io.Writer, - io.StringWriter, - io.ByteWriter, -): - """ - A string builder class that allows for efficient string management and concatenation. - This class is useful when you need to build a string by appending multiple strings - together. The performance increase is not linear. Compared to string concatenation, - I've observed around 20-30x faster for writing and rending ~4KB and up to 2100x-2300x - for ~4MB. This is because it avoids the overhead of creating and destroying many - intermediate strings and performs memcopy operations. - - The result is a more efficient when building larger string concatenations. It - is generally not recommended to use this class for small concatenations such as - a few strings like `a + b + c + d` because the overhead of creating the string - builder and appending the strings is not worth the performance gain. - - Example: - ``` - from strings.builder import StringBuilder - - var sb = StringBuilder() - sb.write_string("Hello ") - sb.write_string("World!") - print(sb) # Hello World! - ``` - """ - - var _data: UnsafePointer[UInt8] - var _size: Int - var _capacity: Int - - @always_inline - fn __init__(inout self, *, capacity: Int = 4096): - constrained[growth_factor >= 1.25]() - self._data = UnsafePointer[UInt8]().alloc(capacity) - self._size = 0 - self._capacity = capacity - - @always_inline - fn __moveinit__(inout self, owned other: Self): - self._data = other._data - self._size = other._size - self._capacity = other._capacity - other._data = UnsafePointer[UInt8]() - other._size = 0 - other._capacity = 0 - - @always_inline - fn __del__(owned self): - if self._data: - self._data.free() - - @always_inline - fn __len__(self) -> Int: - """Returns the length of the string builder.""" - return self._size - - @always_inline - fn __str__(self) -> String: - """ - Converts the string builder to a string. - - Returns: - The string representation of the string builder. Returns an empty - string if the string builder is empty. - """ - var copy = UnsafePointer[UInt8]().alloc(self._size) - memcpy(copy, self._data, self._size) - return StringRef(copy, self._size) - - @always_inline - fn as_bytes_slice(self: Reference[Self]) -> Span[UInt8, self.is_mutable, self.lifetime]: - """Returns the internal _data as a Span[UInt8].""" - return Span[UInt8, self.is_mutable, self.lifetime](unsafe_ptr=self[]._data, len=self[]._size) - - @always_inline - fn render( - self: Reference[Self], - ) -> StringSlice[self.is_mutable, self.lifetime]: - """ - Return a StringSlice view of the _data owned by the builder. - Slightly faster than __str__, 10-20% faster in limited testing. - - Returns: - The string representation of the string builder. Returns an empty string if the string builder is empty. - """ - return StringSlice[self.is_mutable, self.lifetime](unsafe_from_utf8_ptr=self[]._data, len=self[]._size) - - @always_inline - fn _resize(inout self, _capacity: Int) -> None: - """ - Resizes the string builder buffer. - - Args: - _capacity: The new _capacity of the string builder buffer. - """ - var new__data = UnsafePointer[UInt8]().alloc(_capacity) - memcpy(new__data, self._data, self._size) - self._data.free() - self._data = new__data - self._capacity = _capacity - - return None - - @always_inline - fn _resize_if_needed(inout self, bytes_to_add: Int): - """Resizes the buffer if the bytes to add exceeds the current capacity.""" - # TODO: Handle the case where new_capacity is greater than MAX_INT. It should panic. - if bytes_to_add > self._capacity - self._size: - var new_capacity = int(self._capacity * 2) - if new_capacity < self._capacity + bytes_to_add: - new_capacity = self._capacity + bytes_to_add - self._resize(new_capacity) - - @always_inline - fn _write(inout self, src: Span[UInt8]) -> (Int, Error): - """ - Appends a byte Span to the builder buffer. - - Args: - src: The byte array to append. - """ - self._resize_if_needed(len(src)) - memcpy(self._data.offset(self._size), src._data, len(src)) - self._size += len(src) - - return len(src), Error() - - @always_inline - fn write(inout self, src: List[UInt8]) -> (Int, Error): - """ - Appends a byte List to the builder buffer. - - Args: - src: The byte array to append. - """ - var span = Span(src) - - var bytes_read: Int - var err: Error - bytes_read, err = self._write(span) - - return bytes_read, err - - @always_inline - fn write_string(inout self, src: String) -> (Int, Error): - """ - Appends a string to the builder buffer. - - Args: - src: The string to append. - """ - return self._write(src.as_bytes_slice()) - - @always_inline - fn write_byte(inout self, byte: UInt8) -> (Int, Error): - self._resize_if_needed(1) - self._data[self._size] = byte - self._size += 1 - return 1, Error() diff --git a/external/gojo/strings/reader.mojo b/external/gojo/strings/reader.mojo deleted file mode 100644 index 97ca0d9..0000000 --- a/external/gojo/strings/reader.mojo +++ /dev/null @@ -1,291 +0,0 @@ -import ..io -from ..builtins import copy, panic - - -@value -# TODO: Uncomment write_to and write_buf once the bug with the trait's Span argument is fixed. -struct Reader( - Sized, - io.Reader, - io.ReaderAt, - io.ByteReader, - io.ByteScanner, - io.Seeker, - # io.WriterTo, -): - """A Reader that implements the [io.Reader], [io.ReaderAt], [io.ByteReader], [io.ByteScanner], [io.Seeker], and [io.WriterTo] traits - by reading from a string. The zero value for Reader operates like a Reader of an empty string. - """ - - var string: String - var read_pos: Int # current reading index - var prev_rune: Int # index of previous rune; or < 0 - - @always_inline - fn __init__(inout self, string: String = ""): - self.string = string - self.read_pos = 0 - self.prev_rune = -1 - - @always_inline - fn __len__(self) -> Int: - """Returns the number of bytes of the unread portion of the string. - - Returns: - int: the number of bytes of the unread portion of the string. - """ - if self.read_pos >= len(self.string): - return 0 - - return len(self.string) - self.read_pos - - @always_inline - fn size(self) -> Int: - """Returns the original length of the underlying string. - size is the number of bytes available for reading via [Reader.read_at]. - The returned value is always the same and is not affected by calls - to any other method. - - Returns: - The original length of the underlying string. - """ - return len(self.string) - - @always_inline - fn _read(inout self, inout dest: Span[UInt8, True], capacity: Int) -> (Int, Error): - """Reads from the underlying string into the provided List[UInt8] object. - Implements the [io.Reader] trait. - - Args: - dest: The destination List[UInt8] object to read into. - capacity: The capacity of the destination List[UInt8] object. - - Returns: - The number of bytes read into dest. - """ - if self.read_pos >= len(self.string): - return 0, io.EOF - - self.prev_rune = -1 - var bytes_written = copy(dest, self.string.as_bytes_slice()[self.read_pos :]) - self.read_pos += bytes_written - return bytes_written, Error() - - @always_inline - fn read(inout self, inout dest: List[UInt8]) -> (Int, Error): - """Reads from the underlying string into the provided List[UInt8] object. - Implements the [io.Reader] trait. - - Args: - dest: The destination List[UInt8] object to read into. - - Returns: - The number of bytes read into dest. - """ - var span = Span(dest) - - var bytes_read: Int - var err: Error - bytes_read, err = self._read(span, dest.capacity) - dest.size += bytes_read - - return bytes_read, err - - @always_inline - fn _read_at(self, inout dest: Span[UInt8, True], off: Int, capacity: Int) -> (Int, Error): - """Reads from the Reader into the dest List[UInt8] starting at the offset off. - It returns the number of bytes read into dest and an error if any. - - Args: - dest: The destination List[UInt8] object to read into. - off: The byte offset to start reading from. - capacity: The capacity of the destination List[UInt8] object. - - Returns: - The number of bytes read into dest. - """ - # cannot modify state - see io.ReaderAt - if off < 0: - return 0, Error("strings.Reader.read_at: negative offset") - - if off >= len(self.string): - return 0, io.EOF - - var error = Error() - var copied_elements_count = copy(dest, self.string.as_bytes_slice()[off:]) - if copied_elements_count < len(dest): - error = Error(str(io.EOF)) - - return copied_elements_count, error - - @always_inline - fn read_at(self, inout dest: List[UInt8], off: Int) -> (Int, Error): - """Reads from the Reader into the dest List[UInt8] starting at the offset off. - It returns the number of bytes read into dest and an error if any. - - Args: - dest: The destination List[UInt8] object to read into. - off: The byte offset to start reading from. - - Returns: - The number of bytes read into dest. - """ - var span = Span(dest) - - var bytes_read: Int - var err: Error - bytes_read, err = self._read_at(span, off, dest.capacity) - dest.size += bytes_read - - return bytes_read, err - - @always_inline - fn read_byte(inout self) -> (UInt8, Error): - """Reads the next byte from the underlying string.""" - self.prev_rune = -1 - if self.read_pos >= len(self.string): - return UInt8(0), io.EOF - - var b = self.string.as_bytes_slice()[self.read_pos] - self.read_pos += 1 - return UInt8(b), Error() - - @always_inline - fn unread_byte(inout self) -> Error: - """Unreads the last byte read. Only the most recent byte read can be unread.""" - if self.read_pos <= 0: - return Error("strings.Reader.unread_byte: at beginning of string") - - self.prev_rune = -1 - self.read_pos -= 1 - - return Error() - - # # read_rune implements the [io.RuneReader] trait. - # fn read_rune() (ch rune, size int, err error): - # if self.read_pos >= Int(len(self.string)): - # self.prev_rune = -1 - # return 0, 0, io.EOF - - # self.prev_rune = int(self.read_pos) - # if c = self.string[self.read_pos]; c < utf8.RuneSelf: - # self.read_pos += 1 - # return rune(c), 1, nil - - # ch, size = utf8.DecodeRuneInString(self.string[self.read_pos:]) - # self.read_pos += Int(size) - # return - - # # unread_rune implements the [io.RuneScanner] trait. - # fn unread_rune() error: - # if self.read_pos <= 0: - # return errors.New("strings.Reader.unread_rune: at beginning of string") - - # if self.prev_rune < 0: - # return errors.New("strings.Reader.unread_rune: previous operation was not read_rune") - - # self.read_pos = Int(self.prev_rune) - # self.prev_rune = -1 - # return nil - - fn seek(inout self, offset: Int, whence: Int) -> (Int, Error): - """Seeks to a new position in the underlying string. The next read will start from that position. - - Args: - offset: The offset to seek to. - whence: The seek mode. It can be one of [io.SEEK_START], [io.SEEK_CURRENT], or [io.SEEK_END]. - - Returns: - The new position in the string. - """ - self.prev_rune = -1 - var position: Int = 0 - - if whence == io.SEEK_START: - position = offset - elif whence == io.SEEK_CURRENT: - position = self.read_pos + offset - elif whence == io.SEEK_END: - position = Int(len(self.string)) + offset - else: - return Int(0), Error("strings.Reader.seek: invalid whence") - - if position < 0: - return Int(0), Error("strings.Reader.seek: negative position") - - self.read_pos = position - return position, Error() - - # fn write_to[W: io.Writer](inout self, inout writer: W) -> (Int, Error): - # """Writes the remaining portion of the underlying string to the provided writer. - # Implements the [io.WriterTo] trait. - - # Args: - # writer: The writer to write the remaining portion of the string to. - - # Returns: - # The number of bytes written to the writer. - # """ - # self.prev_rune = -1 - # var err = Error() - # if self.read_pos >= len(self.string): - # return Int(0), err - - # var chunk_to_write = self.string.as_bytes_slice()[self.read_pos :] - # var bytes_written: Int - # bytes_written, err = writer.write(chunk_to_write) - # if bytes_written > len(chunk_to_write): - # panic("strings.Reader.write_to: invalid write_string count") - - # self.read_pos += bytes_written - # if bytes_written != len(chunk_to_write) and not err: - # err = Error(io.ERR_SHORT_WRITE) - - # return bytes_written, err - - # # TODO: How can I differentiate between the two write_to methods when the writer implements both traits? - # fn write_to[W: io.StringWriter](inout self, inout writer: W) raises -> Int: - # """Writes the remaining portion of the underlying string to the provided writer. - # Implements the [io.WriterTo] trait. - - # Args: - # writer: The writer to write the remaining portion of the string to. - - # Returns: - # The number of bytes written to the writer. - # """ - # self.prev_rune = -1 - # if self.read_pos >= Int(len(self.string)): - # return 0 - - # var chunk_to_write = self.string[self.read_pos:] - # var bytes_written = io.write_string(writer, chunk_to_write) - # if bytes_written > len(chunk_to_write): - # raise Error("strings.Reader.write_to: invalid write_string count") - - # self.read_pos += Int(bytes_written) - # if bytes_written != len(chunk_to_write): - # raise Error(io.ERR_SHORT_WRITE) - - # return Int(bytes_written) - - @always_inline - fn reset(inout self, string: String): - """Resets the [Reader] to be reading from the beginning of the provided string. - - Args: - string: The string to read from. - """ - self.string = string - self.read_pos = 0 - self.prev_rune = -1 - - -fn new_reader(string: String = "") -> Reader: - """Returns a new [Reader] reading from the provided string. - It is similar to [bytes.new_buffer] but more efficient and non-writable. - - Args: - string: The string to read from. - """ - return Reader(string) diff --git a/external/gojo/syscall/__init__.mojo b/external/gojo/syscall/__init__.mojo deleted file mode 100644 index c89fef0..0000000 --- a/external/gojo/syscall/__init__.mojo +++ /dev/null @@ -1,62 +0,0 @@ -from .net import ( - FD, - SocketType, - AddressFamily, - ProtocolFamily, - SocketOptions, - AddressInformation, - send, - sendto, - recv, - recvfrom, - open, - addrinfo, - addrinfo_unix, - sockaddr, - sockaddr_in, - socklen_t, - socket, - connect, - htons, - ntohs, - inet_pton, - inet_ntop, - getaddrinfo, - getaddrinfo_unix, - gai_strerror, - shutdown, - inet_ntoa, - bind, - listen, - accept, - setsockopt, - getsockopt, - getsockname, - getpeername, - SHUT_RDWR, - SOL_SOCKET, -) -from .file import close, FileDescriptorBase - -# Adapted from https://github.com/crisadamo/mojo-Libc . Huge thanks to Cristian! -# C types -alias c_void = UInt8 -alias c_char = UInt8 -alias c_schar = Int8 -alias c_uchar = UInt8 -alias c_short = Int16 -alias c_ushort = UInt16 -alias c_int = Int32 -alias c_uint = UInt32 -alias c_long = Int64 -alias c_ulong = UInt64 -alias c_float = Float32 -alias c_double = Float64 - -# `Int` is known to be machine's width -alias c_size_t = Int -alias c_ssize_t = Int - -alias ptrdiff_t = Int64 -alias intptr_t = Int64 -alias uintptr_t = UInt64 diff --git a/external/gojo/syscall/file.mojo b/external/gojo/syscall/file.mojo deleted file mode 100644 index ef0427e..0000000 --- a/external/gojo/syscall/file.mojo +++ /dev/null @@ -1,63 +0,0 @@ -trait FileDescriptorBase(io.Reader, io.Writer, io.Closer): - ... - - -# --- ( File Related Syscalls & Structs )--------------------------------------- -alias O_NONBLOCK = 16384 -alias O_ACCMODE = 3 -alias O_CLOEXEC = 524288 - - -fn close(fildes: c_int) -> c_int: - """Libc POSIX `close` function - Reference: https://man7.org/linux/man-pages/man3/close.3p.html - Fn signature: int close(int fildes). - - Args: - fildes: A File Descriptor to close. - - Returns: - Upon successful completion, 0 shall be returned; otherwise, -1 - shall be returned and errno set to indicate the error. - """ - return external_call["close", c_int, c_int](fildes) - - -fn open[*T: AnyType](path: UnsafePointer[c_char], oflag: c_int) -> c_int: - """Libc POSIX `open` function - Reference: https://man7.org/linux/man-pages/man3/open.3p.html - Fn signature: int open(const char *path, int oflag, ...). - - Args: - path: A pointer to a C string containing the path to open. - oflag: The flags to open the file with. - Returns: - A File Descriptor or -1 in case of failure - """ - return external_call["open", c_int, UnsafePointer[c_char], c_int](path, oflag) # FnName, RetType # Args - - -fn read(fildes: c_int, buf: UnsafePointer[c_void], nbyte: c_size_t) -> c_int: - """Libc POSIX `read` function - Reference: https://man7.org/linux/man-pages/man3/read.3p.html - Fn signature: sssize_t read(int fildes, void *buf, size_t nbyte). - - Args: fildes: A File Descriptor. - buf: A pointer to a buffer to store the read data. - nbyte: The number of bytes to read. - Returns: The number of bytes read or -1 in case of failure. - """ - return external_call["read", c_ssize_t, c_int, UnsafePointer[c_void], c_size_t](fildes, buf, nbyte) - - -fn write(fildes: c_int, buf: UnsafePointer[c_void], nbyte: c_size_t) -> c_int: - """Libc POSIX `write` function - Reference: https://man7.org/linux/man-pages/man3/write.3p.html - Fn signature: ssize_t write(int fildes, const void *buf, size_t nbyte). - - Args: fildes: A File Descriptor. - buf: A pointer to a buffer to write. - nbyte: The number of bytes to write. - Returns: The number of bytes written or -1 in case of failure. - """ - return external_call["write", c_ssize_t, c_int, UnsafePointer[c_void], c_size_t](fildes, buf, nbyte) diff --git a/external/gojo/syscall/net.mojo b/external/gojo/syscall/net.mojo deleted file mode 100644 index 676b2da..0000000 --- a/external/gojo/syscall/net.mojo +++ /dev/null @@ -1,915 +0,0 @@ -from . import c_char, c_int, c_ushort, c_uint, c_size_t, c_ssize_t -from .file import O_CLOEXEC, O_NONBLOCK -from utils.static_tuple import StaticTuple - -alias IPPROTO_IPV6 = 41 -alias IPV6_V6ONLY = 26 -alias EPROTONOSUPPORT = 93 - -# Adapted from https://github.com/gabrieldemarmiesse/mojo-stdlib-extensions/ . Huge thanks to Gabriel! - - -struct FD: - alias STDIN = 0 - alias STDOUT = 1 - alias STDERR = 2 - - -alias SUCCESS = 0 -alias GRND_NONBLOCK: UInt8 = 1 - -alias char_pointer = UnsafePointer[UInt8] - - -# --- ( error.h Constants )----------------------------------------------------- -struct ErrnoConstants: - alias EPERM = 1 - alias ENOENT = 2 - alias ESRCH = 3 - alias EINTR = 4 - alias EIO = 5 - alias ENXIO = 6 - alias E2BIG = 7 - alias ENOEXEC = 8 - alias EBADF = 9 - alias ECHILD = 10 - alias EAGAIN = 11 - alias ENOMEM = 12 - alias EACCES = 13 - alias EFAULT = 14 - alias ENOTBLK = 15 - alias EBUSY = 16 - alias EEXIST = 17 - alias EXDEV = 18 - alias ENODEV = 19 - alias ENOTDIR = 20 - alias EISDIR = 21 - alias EINVAL = 22 - alias ENFILE = 23 - alias EMFILE = 24 - alias ENOTTY = 25 - alias ETXTBSY = 26 - alias EFBIG = 27 - alias ENOSPC = 28 - alias ESPIPE = 29 - alias EROFS = 30 - alias EMLINK = 31 - alias EPIPE = 32 - alias EDOM = 33 - alias ERANGE = 34 - alias EWOULDBLOCK = 11 - - -# fn to_char_ptr(s: String) -> UnsafePointer[UInt8]: -# """Only ASCII-based strings.""" -# var ptr = UnsafePointer[UInt8]().alloc(len(s)) -# for i in range(len(s)): -# ptr.store(i, ord(s[i])) -# return ptr - - -fn cftob(val: c_int) -> Bool: - """Convert C-like failure (-1) to Bool.""" - return rebind[Bool](val > 0) - - -# --- ( Network Related Constants )--------------------------------------------- -alias sa_family_t = c_ushort -alias socklen_t = c_uint -alias in_addr_t = c_uint -alias in_port_t = c_ushort - - -# Address Family Constants -struct AddressFamily: - alias AF_UNSPEC = 0 - alias AF_UNIX = 1 - alias AF_LOCAL = 1 - alias AF_INET = 2 - alias AF_AX25 = 3 - alias AF_IPX = 4 - alias AF_APPLETALK = 5 - alias AF_NETROM = 6 - alias AF_BRIDGE = 7 - alias AF_ATMPVC = 8 - alias AF_X25 = 9 - alias AF_INET6 = 10 - alias AF_ROSE = 11 - alias AF_DECnet = 12 - alias AF_NETBEUI = 13 - alias AF_SECURITY = 14 - alias AF_KEY = 15 - alias AF_NETLINK = 16 - alias AF_ROUTE = 16 - alias AF_PACKET = 17 - alias AF_ASH = 18 - alias AF_ECONET = 19 - alias AF_ATMSVC = 20 - alias AF_RDS = 21 - alias AF_SNA = 22 - alias AF_IRDA = 23 - alias AF_PPPOX = 24 - alias AF_WANPIPE = 25 - alias AF_LLC = 26 - alias AF_CAN = 29 - alias AF_TIPC = 30 - alias AF_BLUETOOTH = 31 - alias AF_IUCV = 32 - alias AF_RXRPC = 33 - alias AF_ISDN = 34 - alias AF_PHONET = 35 - alias AF_IEEE802154 = 36 - alias AF_CAIF = 37 - alias AF_ALG = 38 - alias AF_NFC = 39 - alias AF_VSOCK = 40 - alias AF_KCM = 41 - alias AF_QIPCRTR = 42 - alias AF_MAX = 43 - - -# Protocol family constants -struct ProtocolFamily: - alias PF_UNSPEC = AddressFamily.AF_UNSPEC - alias PF_UNIX = AddressFamily.AF_UNIX - alias PF_LOCAL = AddressFamily.AF_LOCAL - alias PF_INET = AddressFamily.AF_INET - alias PF_AX25 = AddressFamily.AF_AX25 - alias PF_IPX = AddressFamily.AF_IPX - alias PF_APPLETALK = AddressFamily.AF_APPLETALK - alias PF_NETROM = AddressFamily.AF_NETROM - alias PF_BRIDGE = AddressFamily.AF_BRIDGE - alias PF_ATMPVC = AddressFamily.AF_ATMPVC - alias PF_X25 = AddressFamily.AF_X25 - alias PF_INET6 = AddressFamily.AF_INET6 - alias PF_ROSE = AddressFamily.AF_ROSE - alias PF_DECnet = AddressFamily.AF_DECnet - alias PF_NETBEUI = AddressFamily.AF_NETBEUI - alias PF_SECURITY = AddressFamily.AF_SECURITY - alias PF_KEY = AddressFamily.AF_KEY - alias PF_NETLINK = AddressFamily.AF_NETLINK - alias PF_ROUTE = AddressFamily.AF_ROUTE - alias PF_PACKET = AddressFamily.AF_PACKET - alias PF_ASH = AddressFamily.AF_ASH - alias PF_ECONET = AddressFamily.AF_ECONET - alias PF_ATMSVC = AddressFamily.AF_ATMSVC - alias PF_RDS = AddressFamily.AF_RDS - alias PF_SNA = AddressFamily.AF_SNA - alias PF_IRDA = AddressFamily.AF_IRDA - alias PF_PPPOX = AddressFamily.AF_PPPOX - alias PF_WANPIPE = AddressFamily.AF_WANPIPE - alias PF_LLC = AddressFamily.AF_LLC - alias PF_CAN = AddressFamily.AF_CAN - alias PF_TIPC = AddressFamily.AF_TIPC - alias PF_BLUETOOTH = AddressFamily.AF_BLUETOOTH - alias PF_IUCV = AddressFamily.AF_IUCV - alias PF_RXRPC = AddressFamily.AF_RXRPC - alias PF_ISDN = AddressFamily.AF_ISDN - alias PF_PHONET = AddressFamily.AF_PHONET - alias PF_IEEE802154 = AddressFamily.AF_IEEE802154 - alias PF_CAIF = AddressFamily.AF_CAIF - alias PF_ALG = AddressFamily.AF_ALG - alias PF_NFC = AddressFamily.AF_NFC - alias PF_VSOCK = AddressFamily.AF_VSOCK - alias PF_KCM = AddressFamily.AF_KCM - alias PF_QIPCRTR = AddressFamily.AF_QIPCRTR - alias PF_MAX = AddressFamily.AF_MAX - - -# Socket Type constants -struct SocketType: - alias SOCK_STREAM = 1 - alias SOCK_DGRAM = 2 - alias SOCK_RAW = 3 - alias SOCK_RDM = 4 - alias SOCK_SEQPACKET = 5 - alias SOCK_DCCP = 6 - alias SOCK_PACKET = 10 - alias SOCK_CLOEXEC = O_CLOEXEC - alias SOCK_NONBLOCK = O_NONBLOCK - - -# Address Information -struct AddressInformation: - alias AI_PASSIVE = 1 - alias AI_CANONNAME = 2 - alias AI_NUMERICHOST = 4 - alias AI_V4MAPPED = 2048 - alias AI_ALL = 256 - alias AI_ADDRCONFIG = 1024 - alias AI_IDN = 64 - - -alias INET_ADDRSTRLEN = 16 -alias INET6_ADDRSTRLEN = 46 - -alias SHUT_RD = 0 -alias SHUT_WR = 1 -alias SHUT_RDWR = 2 - -alias SOL_SOCKET = 65535 - - -# Socket Options -struct SocketOptions: - alias SO_DEBUG = 1 - alias SO_REUSEADDR = 4 - alias SO_TYPE = 4104 - alias SO_ERROR = 4103 - alias SO_DONTROUTE = 16 - alias SO_BROADCAST = 32 - alias SO_SNDBUF = 4097 - alias SO_RCVBUF = 4098 - alias SO_KEEPALIVE = 8 - alias SO_OOBINLINE = 256 - alias SO_LINGER = 128 - alias SO_REUSEPORT = 512 - alias SO_RCVLOWAT = 4100 - alias SO_SNDLOWAT = 4099 - alias SO_RCVTIMEO = 4102 - alias SO_SNDTIMEO = 4101 - alias SO_RCVTIMEO_OLD = 4102 - alias SO_SNDTIMEO_OLD = 4101 - alias SO_ACCEPTCONN = 2 - # unsure of these socket options, they weren't available via python - alias SO_NO_CHECK = 11 - alias SO_PRIORITY = 12 - alias SO_BSDCOMPAT = 14 - alias SO_PASSCRED = 16 - alias SO_PEERCRED = 17 - alias SO_SECURITY_AUTHENTICATION = 22 - alias SO_SECURITY_ENCRYPTION_TRANSPORT = 23 - alias SO_SECURITY_ENCRYPTION_NETWORK = 24 - alias SO_BINDTODEVICE = 25 - alias SO_ATTACH_FILTER = 26 - alias SO_DETACH_FILTER = 27 - alias SO_GET_FILTER = 26 - alias SO_PEERNAME = 28 - alias SO_TIMESTAMP = 29 - alias SO_TIMESTAMP_OLD = 29 - alias SO_PEERSEC = 31 - alias SO_SNDBUFFORCE = 32 - alias SO_RCVBUFFORCE = 33 - alias SO_PASSSEC = 34 - alias SO_TIMESTAMPNS = 35 - alias SO_TIMESTAMPNS_OLD = 35 - alias SO_MARK = 36 - alias SO_TIMESTAMPING = 37 - alias SO_TIMESTAMPING_OLD = 37 - alias SO_PROTOCOL = 38 - alias SO_DOMAIN = 39 - alias SO_RXQ_OVFL = 40 - alias SO_WIFI_STATUS = 41 - alias SCM_WIFI_STATUS = 41 - alias SO_PEEK_OFF = 42 - alias SO_NOFCS = 43 - alias SO_LOCK_FILTER = 44 - alias SO_SELECT_ERR_QUEUE = 45 - alias SO_BUSY_POLL = 46 - alias SO_MAX_PACING_RATE = 47 - alias SO_BPF_EXTENSIONS = 48 - alias SO_INCOMING_CPU = 49 - alias SO_ATTACH_BPF = 50 - alias SO_DETACH_BPF = 27 - alias SO_ATTACH_REUSEPORT_CBPF = 51 - alias SO_ATTACH_REUSEPORT_EBPF = 52 - alias SO_CNX_ADVICE = 53 - alias SCM_TIMESTAMPING_OPT_STATS = 54 - alias SO_MEMINFO = 55 - alias SO_INCOMING_NAPI_ID = 56 - alias SO_COOKIE = 57 - alias SCM_TIMESTAMPING_PKTINFO = 58 - alias SO_PEERGROUPS = 59 - alias SO_ZEROCOPY = 60 - alias SO_TXTIME = 61 - alias SCM_TXTIME = 61 - alias SO_BINDTOIFINDEX = 62 - alias SO_TIMESTAMP_NEW = 63 - alias SO_TIMESTAMPNS_NEW = 64 - alias SO_TIMESTAMPING_NEW = 65 - alias SO_RCVTIMEO_NEW = 66 - alias SO_SNDTIMEO_NEW = 67 - alias SO_DETACH_REUSEPORT_BPF = 68 - - -# --- ( Network Related Structs )----------------------------------------------- -@value -@register_passable("trivial") -struct in_addr: - var s_addr: in_addr_t - - -@value -@register_passable("trivial") -struct in6_addr: - var s6_addr: StaticTuple[c_char, 16] - - -@value -@register_passable("trivial") -struct sockaddr: - var sa_family: sa_family_t - var sa_data: StaticTuple[c_char, 14] - - -@value -@register_passable("trivial") -struct sockaddr_in: - var sin_family: sa_family_t - var sin_port: in_port_t - var sin_addr: in_addr - var sin_zero: StaticTuple[c_char, 8] - - -@value -@register_passable("trivial") -struct sockaddr_in6: - var sin6_family: sa_family_t - var sin6_port: in_port_t - var sin6_flowinfo: c_uint - var sin6_addr: in6_addr - var sin6_scope_id: c_uint - - -@value -@register_passable("trivial") -struct addrinfo: - """Struct field ordering can vary based on platform. - For MacOS, I had to swap the order of ai_canonname and ai_addr. - https://stackoverflow.com/questions/53575101/calling-getaddrinfo-directly-from-python-ai-addr-is-null-pointer. - """ - - var ai_flags: c_int - var ai_family: c_int - var ai_socktype: c_int - var ai_protocol: c_int - var ai_addrlen: socklen_t - var ai_canonname: UnsafePointer[UInt8] - var ai_addr: UnsafePointer[sockaddr] - var ai_next: UnsafePointer[addrinfo] - - fn __init__( - inout self, - ai_flags: c_int = 0, - ai_family: c_int = 0, - ai_socktype: c_int = 0, - ai_protocol: c_int = 0, - ai_addrlen: socklen_t = 0, - ai_canonname: UnsafePointer[UInt8] = UnsafePointer[UInt8](), - ai_addr: UnsafePointer[sockaddr] = UnsafePointer[sockaddr](), - ai_next: UnsafePointer[addrinfo] = UnsafePointer[addrinfo](), - ): - self.ai_flags = ai_flags - self.ai_family = ai_family - self.ai_socktype = ai_socktype - self.ai_protocol = ai_protocol - self.ai_addrlen = ai_addrlen - self.ai_canonname = ai_canonname - self.ai_addr = ai_addr - self.ai_next = ai_next - - # fn __init__() -> Self: - # return Self(0, 0, 0, 0, 0, UnsafePointer[UInt8](), UnsafePointer[sockaddr](), UnsafePointer[addrinfo]()) - - -@value -@register_passable("trivial") -struct addrinfo_unix: - """Struct field ordering can vary based on platform. - For MacOS, I had to swap the order of ai_canonname and ai_addr. - https://stackoverflow.com/questions/53575101/calling-getaddrinfo-directly-from-python-ai-addr-is-null-pointer. - """ - - var ai_flags: c_int - var ai_family: c_int - var ai_socktype: c_int - var ai_protocol: c_int - var ai_addrlen: socklen_t - var ai_addr: UnsafePointer[sockaddr] - var ai_canonname: UnsafePointer[UInt8] - var ai_next: UnsafePointer[addrinfo] - - fn __init__( - inout self, - ai_flags: c_int = 0, - ai_family: c_int = 0, - ai_socktype: c_int = 0, - ai_protocol: c_int = 0, - ai_addrlen: socklen_t = 0, - ai_canonname: UnsafePointer[UInt8] = UnsafePointer[UInt8](), - ai_addr: UnsafePointer[sockaddr] = UnsafePointer[sockaddr](), - ai_next: UnsafePointer[addrinfo] = UnsafePointer[addrinfo](), - ): - self.ai_flags = ai_flags - self.ai_family = ai_family - self.ai_socktype = ai_socktype - self.ai_protocol = ai_protocol - self.ai_addrlen = ai_addrlen - self.ai_canonname = ai_canonname - self.ai_addr = ai_addr - self.ai_next = ai_next - - -# --- ( Network Related Syscalls & Structs )------------------------------------ - - -fn htonl(hostlong: c_uint) -> c_uint: - """Libc POSIX `htonl` function - Reference: https://man7.org/linux/man-pages/man3/htonl.3p.html - Fn signature: uint32_t htonl(uint32_t hostlong). - - Args: hostlong: A 32-bit integer in host byte order. - Returns: The value provided in network byte order. - """ - return external_call["htonl", c_uint, c_uint](hostlong) - - -fn htons(hostshort: c_ushort) -> c_ushort: - """Libc POSIX `htons` function - Reference: https://man7.org/linux/man-pages/man3/htonl.3p.html - Fn signature: uint16_t htons(uint16_t hostshort). - - Args: hostshort: A 16-bit integer in host byte order. - Returns: The value provided in network byte order. - """ - return external_call["htons", c_ushort, c_ushort](hostshort) - - -fn ntohl(netlong: c_uint) -> c_uint: - """Libc POSIX `ntohl` function - Reference: https://man7.org/linux/man-pages/man3/htonl.3p.html - Fn signature: uint32_t ntohl(uint32_t netlong). - - Args: netlong: A 32-bit integer in network byte order. - Returns: The value provided in host byte order. - """ - return external_call["ntohl", c_uint, c_uint](netlong) - - -fn ntohs(netshort: c_ushort) -> c_ushort: - """Libc POSIX `ntohs` function - Reference: https://man7.org/linux/man-pages/man3/htonl.3p.html - Fn signature: uint16_t ntohs(uint16_t netshort). - - Args: netshort: A 16-bit integer in network byte order. - Returns: The value provided in host byte order. - """ - return external_call["ntohs", c_ushort, c_ushort](netshort) - - -fn inet_ntop( - af: c_int, - src: UnsafePointer[UInt8], - dst: UnsafePointer[UInt8], - size: socklen_t, -) -> UnsafePointer[UInt8]: - """Libc POSIX `inet_ntop` function - Reference: https://man7.org/linux/man-pages/man3/inet_ntop.3p.html. - Fn signature: const char *inet_ntop(int af, const void *restrict src, char *restrict dst, socklen_t size). - - Args: - af: Address Family see AF_ aliases. - src: A pointer to a binary address. - dst: A pointer to a buffer to store the result. - size: The size of the buffer. - - Returns: - A pointer to the buffer containing the result. - """ - return external_call[ - "inet_ntop", - UnsafePointer[UInt8], # FnName, RetType - c_int, - UnsafePointer[UInt8], - UnsafePointer[UInt8], - socklen_t, # Args - ](af, src, dst, size) - - -fn inet_pton(af: c_int, src: UnsafePointer[UInt8], dst: UnsafePointer[UInt8]) -> c_int: - """Libc POSIX `inet_pton` function - Reference: https://man7.org/linux/man-pages/man3/inet_ntop.3p.html - Fn signature: int inet_pton(int af, const char *restrict src, void *restrict dst). - - Args: af: Address Family see AF_ aliases. - src: A pointer to a string containing the address. - dst: A pointer to a buffer to store the result. - Returns: 1 on success, 0 if the input is not a valid address, -1 on error. - """ - return external_call[ - "inet_pton", - c_int, # FnName, RetType - c_int, - UnsafePointer[UInt8], - UnsafePointer[UInt8], # Args - ](af, src, dst) - - -fn inet_addr(cp: UnsafePointer[UInt8]) -> in_addr_t: - """Libc POSIX `inet_addr` function - Reference: https://man7.org/linux/man-pages/man3/inet_addr.3p.html - Fn signature: in_addr_t inet_addr(const char *cp). - - Args: cp: A pointer to a string containing the address. - Returns: The address in network byte order. - """ - return external_call["inet_addr", in_addr_t, UnsafePointer[UInt8]](cp) - - -fn inet_ntoa(addr: in_addr) -> UnsafePointer[UInt8]: - """Libc POSIX `inet_ntoa` function - Reference: https://man7.org/linux/man-pages/man3/inet_addr.3p.html - Fn signature: char *inet_ntoa(struct in_addr in). - - Args: in: A pointer to a string containing the address. - Returns: The address in network byte order. - """ - return external_call["inet_ntoa", UnsafePointer[UInt8], in_addr](addr) - - -fn socket(domain: c_int, type: c_int, protocol: c_int) -> c_int: - """Libc POSIX `socket` function - Reference: https://man7.org/linux/man-pages/man3/socket.3p.html - Fn signature: int socket(int domain, int type, int protocol). - - Args: domain: Address Family see AF_ aliases. - type: Socket Type see SOCK_ aliases. - protocol: The protocol to use. - Returns: A File Descriptor or -1 in case of failure. - """ - return external_call["socket", c_int, c_int, c_int, c_int](domain, type, protocol) # FnName, RetType # Args - - -fn setsockopt( - socket: c_int, - level: c_int, - option_name: c_int, - option_value: UnsafePointer[UInt8], - option_len: socklen_t, -) -> c_int: - """Libc POSIX `setsockopt` function - Reference: https://man7.org/linux/man-pages/man3/setsockopt.3p.html - Fn signature: int setsockopt(int socket, int level, int option_name, const void *option_value, socklen_t option_len). - - Args: - socket: A File Descriptor. - level: The protocol level. - option_name: The option to set. - option_value: A pointer to the value to set. - option_len: The size of the value. - Returns: 0 on success, -1 on error. - """ - return external_call[ - "setsockopt", - c_int, # FnName, RetType - c_int, - c_int, - c_int, - UnsafePointer[UInt8], - socklen_t, # Args - ](socket, level, option_name, option_value, option_len) - - -fn getsockopt( - socket: c_int, - level: c_int, - option_name: c_int, - option_value: UnsafePointer[UInt8], - option_len: UnsafePointer[socklen_t], -) -> c_int: - """Libc POSIX `getsockopt` function - Reference: https://man7.org/linux/man-pages/man3/getsockopt.3p.html - Fn signature: int getsockopt(int socket, int level, int option_name, void *restrict option_value, socklen_t *restrict option_len). - - Args: socket: A File Descriptor. - level: The protocol level. - option_name: The option to get. - option_value: A pointer to the value to get. - option_len: DTypePointer to the size of the value. - Returns: 0 on success, -1 on error. - """ - return external_call[ - "getsockopt", - c_int, # FnName, RetType - c_int, - c_int, - c_int, - UnsafePointer[UInt8], - UnsafePointer[socklen_t], # Args - ](socket, level, option_name, option_value, option_len) - - -fn getsockname( - socket: c_int, - address: UnsafePointer[sockaddr], - address_len: UnsafePointer[socklen_t], -) -> c_int: - """Libc POSIX `getsockname` function - Reference: https://man7.org/linux/man-pages/man3/getsockname.3p.html - Fn signature: int getsockname(int socket, struct sockaddr *restrict address, socklen_t *restrict address_len). - - Args: socket: A File Descriptor. - address: A pointer to a buffer to store the address of the peer. - address_len: A pointer to the size of the buffer. - Returns: 0 on success, -1 on error. - """ - return external_call[ - "getsockname", - c_int, # FnName, RetType - c_int, - UnsafePointer[sockaddr], - UnsafePointer[socklen_t], # Args - ](socket, address, address_len) - - -fn getpeername( - sockfd: c_int, - addr: UnsafePointer[sockaddr], - address_len: UnsafePointer[socklen_t], -) -> c_int: - """Libc POSIX `getpeername` function - Reference: https://man7.org/linux/man-pages/man2/getpeername.2.html - Fn signature: int getpeername(int socket, struct sockaddr *restrict addr, socklen_t *restrict address_len). - - Args: sockfd: A File Descriptor. - addr: A pointer to a buffer to store the address of the peer. - address_len: A pointer to the size of the buffer. - Returns: 0 on success, -1 on error. - """ - return external_call[ - "getpeername", - c_int, # FnName, RetType - c_int, - UnsafePointer[sockaddr], - UnsafePointer[socklen_t], # Args - ](sockfd, addr, address_len) - - -fn bind(socket: c_int, address: UnsafePointer[sockaddr], address_len: socklen_t) -> c_int: - """Libc POSIX `bind` function - Reference: https://man7.org/linux/man-pages/man3/bind.3p.html - Fn signature: int bind(int socket, const struct sockaddr *address, socklen_t address_len). - """ - return external_call["bind", c_int, c_int, UnsafePointer[sockaddr], socklen_t]( # FnName, RetType # Args - socket, address, address_len - ) - - -fn listen(socket: c_int, backlog: c_int) -> c_int: - """Libc POSIX `listen` function - Reference: https://man7.org/linux/man-pages/man3/listen.3p.html - Fn signature: int listen(int socket, int backlog). - - Args: socket: A File Descriptor. - backlog: The maximum length of the queue of pending connections. - Returns: 0 on success, -1 on error. - """ - return external_call["listen", c_int, c_int, c_int](socket, backlog) - - -fn accept( - socket: c_int, - address: UnsafePointer[sockaddr], - address_len: UnsafePointer[socklen_t], -) -> c_int: - """Libc POSIX `accept` function - Reference: https://man7.org/linux/man-pages/man3/accept.3p.html - Fn signature: int accept(int socket, struct sockaddr *restrict address, socklen_t *restrict address_len). - - Args: socket: A File Descriptor. - address: A pointer to a buffer to store the address of the peer. - address_len: A pointer to the size of the buffer. - Returns: A File Descriptor or -1 in case of failure. - """ - return external_call[ - "accept", - c_int, # FnName, RetType - c_int, - UnsafePointer[sockaddr], - UnsafePointer[socklen_t], # Args - ](socket, address, address_len) - - -fn connect(socket: c_int, address: UnsafePointer[sockaddr], address_len: socklen_t) -> c_int: - """Libc POSIX `connect` function - Reference: https://man7.org/linux/man-pages/man3/connect.3p.html - Fn signature: int connect(int socket, const struct sockaddr *address, socklen_t address_len). - - Args: socket: A File Descriptor. - address: A pointer to the address to connect to. - address_len: The size of the address. - Returns: 0 on success, -1 on error. - """ - return external_call["connect", c_int, c_int, UnsafePointer[sockaddr], socklen_t]( # FnName, RetType # Args - socket, address, address_len - ) - - -fn recv( - socket: c_int, - buffer: UnsafePointer[UInt8], - length: c_size_t, - flags: c_int, -) -> c_ssize_t: - """Libc POSIX `recv` function - Reference: https://man7.org/linux/man-pages/man3/recv.3p.html - Fn signature: ssize_t recv(int socket, void *buffer, size_t length, int flags). - - Args: - socket: Specifies the socket file descriptor. - buffer: Points to the buffer where the message should be stored. - length: Specifies the length in bytes of the buffer pointed to by the buffer argument. - flags: Specifies the type of message reception. - - Returns: - The number of bytes received or -1 in case of failure. - - Valid Flags: - MSG_PEEK: Peeks at an incoming message. The data is treated as unread and the next recvfrom() or similar function shall still return this data. - MSG_OOB: Requests out-of-band data. The significance and semantics of out-of-band data are protocol-specific. - MSG_WAITALL: On SOCK_STREAM sockets this requests that the function block until the full amount of data can be returned. The function may return the smaller amount of data if the socket is a message-based socket, if a signal is caught, if the connection is terminated, if MSG_PEEK was specified, or if an error is pending for the socket. - """ - return external_call[ - "recv", - c_ssize_t, - c_int, - UnsafePointer[UInt8], - c_size_t, - c_int, - ](socket, buffer, length, flags) - - -fn recvfrom( - socket: c_int, - buffer: UnsafePointer[UInt8], - length: c_size_t, - flags: c_int, - address: UnsafePointer[sockaddr], - address_len: UnsafePointer[socklen_t], -) -> c_ssize_t: - """Libc POSIX `recvfrom` function - Reference: https://man7.org/linux/man-pages/man3/recvfrom.3p.html - Fn signature: ssize_t recvfrom(int socket, void *restrict buffer, size_t length, - int flags, struct sockaddr *restrict address, - socklen_t *restrict address_len). - - Args: - socket: Specifies the socket file descriptor. - buffer: Points to the buffer where the message should be stored. - length: Specifies the length in bytes of the buffer pointed to by the buffer argument. - flags: Specifies the type of message reception. - address: A null pointer, or points to a sockaddr structure in which the sending address is to be stored. - address_len: Either a null pointer, if address is a null pointer, or a pointer to a socklen_t object which on input specifies the length of the supplied sockaddr structure, and on output specifies the length of the stored address. - - Returns: - The number of bytes received or -1 in case of failure. - - Valid Flags: - MSG_PEEK: Peeks at an incoming message. The data is treated as unread and the next recvfrom() or similar function shall still return this data. - MSG_OOB: Requests out-of-band data. The significance and semantics of out-of-band data are protocol-specific. - MSG_WAITALL: On SOCK_STREAM sockets this requests that the function block until the full amount of data can be returned. The function may return the smaller amount of data if the socket is a message-based socket, if a signal is caught, if the connection is terminated, if MSG_PEEK was specified, or if an error is pending for the socket. - """ - return external_call[ - "recvfrom", - c_ssize_t, - c_int, - UnsafePointer[UInt8], - c_size_t, - c_int, - UnsafePointer[sockaddr], - UnsafePointer[socklen_t], - ](socket, buffer, length, flags, address, address_len) - - -fn send( - socket: c_int, - buffer: UnsafePointer[UInt8], - length: c_size_t, - flags: c_int, -) -> c_ssize_t: - """Libc POSIX `send` function - Reference: https://man7.org/linux/man-pages/man3/send.3p.html - Fn signature: ssize_t send(int socket, const void *buffer, size_t length, int flags). - - Args: socket: A File Descriptor. - buffer: A pointer to the buffer to send. - length: The size of the buffer. - flags: Flags to control the behaviour of the function. - Returns: The number of bytes sent or -1 in case of failure. - """ - return external_call[ - "send", - c_ssize_t, # FnName, RetType - c_int, - UnsafePointer[UInt8], - c_size_t, - c_int, # Args - ](socket, buffer, length, flags) - - -fn sendto( - socket: c_int, - message: UnsafePointer[UInt8], - length: c_size_t, - flags: c_int, - dest_addr: UnsafePointer[sockaddr], - dest_len: socklen_t, -) -> c_ssize_t: - """Libc POSIX `sendto` function - Reference: https://man7.org/linux/man-pages/man3/sendto.3p.html - Fn signature: ssize_t sendto(int socket, const void *message, size_t length, - int flags, const struct sockaddr *dest_addr, - socklen_t dest_len). - - Args: - socket: Specifies the socket file descriptor. - message: Points to a buffer containing the message to be sent. - length: Specifies the size of the message in bytes. - flags: Specifies the type of message transmission. - dest_addr: Points to a sockaddr structure containing the destination address. - dest_len: Specifies the length of the sockaddr. - - Returns: - The number of bytes sent or -1 in case of failure. - - Valid Flags: - MSG_EOR: Terminates a record (if supported by the protocol). - MSG_OOB: Sends out-of-band data on sockets that support out-of-band data. The significance and semantics of out-of-band data are protocol-specific. - MSG_NOSIGNAL: Requests not to send the SIGPIPE signal if an attempt to send is made on a stream-oriented socket that is no longer connected. The [EPIPE] error shall still be returned. - """ - return external_call[ - "sendto", c_ssize_t, c_int, UnsafePointer[UInt8], c_size_t, c_int, UnsafePointer[sockaddr], socklen_t - ](socket, message, length, flags, dest_addr, dest_len) - - -fn shutdown(socket: c_int, how: c_int) -> c_int: - """Libc POSIX `shutdown` function - Reference: https://man7.org/linux/man-pages/man3/shutdown.3p.html - Fn signature: int shutdown(int socket, int how). - - Args: socket: A File Descriptor. - how: How to shutdown the socket. - Returns: 0 on success, -1 on error. - """ - return external_call["shutdown", c_int, c_int, c_int](socket, how) # FnName, RetType # Args - - -fn getaddrinfo( - nodename: UnsafePointer[UInt8], - servname: UnsafePointer[UInt8], - hints: UnsafePointer[addrinfo], - res: UnsafePointer[UnsafePointer[addrinfo]], -) -> c_int: - """Libc POSIX `getaddrinfo` function - Reference: https://man7.org/linux/man-pages/man3/getaddrinfo.3p.html - Fn signature: int getaddrinfo(const char *restrict nodename, const char *restrict servname, const struct addrinfo *restrict hints, struct addrinfo **restrict res). - """ - return external_call[ - "getaddrinfo", - c_int, # FnName, RetType - UnsafePointer[UInt8], - UnsafePointer[UInt8], - UnsafePointer[addrinfo], # Args - UnsafePointer[UnsafePointer[addrinfo]], # Args - ](nodename, servname, hints, res) - - -fn getaddrinfo_unix( - nodename: UnsafePointer[UInt8], - servname: UnsafePointer[UInt8], - hints: UnsafePointer[addrinfo_unix], - res: UnsafePointer[UnsafePointer[addrinfo_unix]], -) -> c_int: - """Libc POSIX `getaddrinfo` function - Reference: https://man7.org/linux/man-pages/man3/getaddrinfo.3p.html - Fn signature: int getaddrinfo(const char *restrict nodename, const char *restrict servname, const struct addrinfo *restrict hints, struct addrinfo **restrict res). - """ - return external_call[ - "getaddrinfo", - c_int, # FnName, RetType - UnsafePointer[UInt8], - UnsafePointer[UInt8], - UnsafePointer[addrinfo_unix], # Args - UnsafePointer[UnsafePointer[addrinfo_unix]], # Args - ](nodename, servname, hints, res) - - -fn gai_strerror(ecode: c_int) -> UnsafePointer[UInt8]: - """Libc POSIX `gai_strerror` function - Reference: https://man7.org/linux/man-pages/man3/gai_strerror.3p.html - Fn signature: const char *gai_strerror(int ecode). - - Args: ecode: The error code. - Returns: A pointer to a string describing the error. - """ - return external_call["gai_strerror", UnsafePointer[UInt8], c_int](ecode) # FnName, RetType # Args - - -# fn inet_pton(address_family: Int, address: String) -> Int: -# var ip_buf_size = 4 -# if address_family == AF_INET6: -# ip_buf_size = 16 - -# var ip_buf = UnsafePointer[UInt8].alloc(ip_buf_size) -# var conv_status = inet_pton(rebind[c_int](address_family), to_char_ptr(address), ip_buf) -# return int(ip_buf.bitcast[c_uint]().load()) diff --git a/external/gojo/unicode/__init__.mojo b/external/gojo/unicode/__init__.mojo deleted file mode 100644 index b300770..0000000 --- a/external/gojo/unicode/__init__.mojo +++ /dev/null @@ -1 +0,0 @@ -from .utf8 import rune_count_in_string, UnicodeString, rune_width, string_width, Condition, DEFAULT_CONDITION diff --git a/external/gojo/unicode/utf8/__init__.mojo b/external/gojo/unicode/utf8/__init__.mojo deleted file mode 100644 index 6f3d8a9..0000000 --- a/external/gojo/unicode/utf8/__init__.mojo +++ /dev/null @@ -1,6 +0,0 @@ -"""Almost all of the actual implementation in this module was written by @mzaks (https://github.com/mzaks)! -This would not be possible without his help. -""" -from .runes import rune_count_in_string -from .string import UnicodeString -from .width import string_width, rune_width, Condition, DEFAULT_CONDITION diff --git a/external/gojo/unicode/utf8/runes.mojo b/external/gojo/unicode/utf8/runes.mojo deleted file mode 100644 index 5171282..0000000 --- a/external/gojo/unicode/utf8/runes.mojo +++ /dev/null @@ -1,33 +0,0 @@ -"""Almost all of the actual implementation in this module was written by @mzaks (https://github.com/mzaks)! -This would not be possible without his help. -""" - -from ...builtins import Rune -from algorithm.functional import vectorize -from sys.info import simdwidthof -from bit import countl_zero - - -# alias simd_width_u8 = simdwidthof[DType.uint8]() -alias simd_width_u8 = 1 - - -fn rune_count_in_string(s: String) -> Int: - """Count the number of runes in a string. - - Args: - s: The string to count runes in. - - Returns: - The number of runes in the string. - """ - var p = DTypePointer[DType.uint8](s.unsafe_uint8_ptr()) - var string_byte_length = len(s) - var result = 0 - - @parameter - fn count[simd_width: Int](offset: Int): - result += int(((p.load[width=simd_width](offset) >> 6) != 0b10).reduce_add()) - - vectorize[count, simd_width_u8](string_byte_length) - return result diff --git a/external/gojo/unicode/utf8/string.mojo b/external/gojo/unicode/utf8/string.mojo deleted file mode 100644 index f0c852d..0000000 --- a/external/gojo/unicode/utf8/string.mojo +++ /dev/null @@ -1,109 +0,0 @@ -from bit import countl_zero -from algorithm.functional import vectorize -from sys.info import simdwidthof - - -alias simd_width_u8 = simdwidthof[DType.uint8]() - - -@value -struct UnicodeString(Stringable, Sized): - """A string that supports Unicode characters. - - The algorithms to handle UTF-8 are from @maxim on the Mojo Discord. Thanks! - """ - - var inner: String - - @always_inline - fn __init__(inout self, owned s: String): - self.inner = s^ - - @always_inline - fn __init__(inout self, owned bytes: List[UInt8]): - if bytes[-1] != 0: - bytes.append(0) - self.inner = String(bytes^) - - @always_inline - fn __len__(self) -> Int: - """Count the number of runes in a string. - - Returns: - The number of runes in the string. - """ - var data = DTypePointer[DType.uint8](self.inner.unsafe_uint8_ptr()) - var byte_count = len(self.inner) - var result = 0 - - @parameter - fn count[simd_width: Int](offset: Int): - result += int(((data.load[width=simd_width](offset) >> 6) != 0b10).cast[DType.uint8]().reduce_add()) - - vectorize[count, simd_width_u8](byte_count) - return result - - @always_inline - fn __str__(self) -> String: - return self.inner - - @always_inline - fn __getitem__(self: Reference[Self], slice: Slice) -> StringSlice[self.is_mutable, self.lifetime]: - """TODO: Doesn't handle negative indices.""" - var bytes_left = len(self[].inner) - var total_char_length: Int = 0 - for _ in range(slice.start, slice.end): - # Number of bytes of the current character - var char_length = int( - (DTypePointer[DType.uint8](self[].inner.unsafe_uint8_ptr() + total_char_length).load() >> 7 == 0).cast[ - DType.uint8 - ]() - * 1 - + countl_zero(~DTypePointer[DType.uint8](self[].inner.unsafe_uint8_ptr() + total_char_length).load()) - ) - - # Move iterator forward - bytes_left -= char_length - total_char_length += char_length - - return StringSlice[self.is_mutable, self.lifetime]( - unsafe_from_utf8_ptr=self[].inner.unsafe_uint8_ptr(), len=total_char_length - ) - - @always_inline - fn bytecount(self) -> Int: - return len(self.inner) - - @always_inline - fn __iter__( - self: Reference[Self], - ) -> _StringIter[self.is_mutable, self.lifetime]: - return _StringIter(self[].inner) - - -@value -struct _StringIter[mutability: Bool, lifetime: AnyLifetime[mutability].type](): - var bytes_left: Int - var ptr: UnsafePointer[UInt8] - - @always_inline - fn __init__(inout self, src: Reference[String, mutability, lifetime]): - self.bytes_left = len(src[]) - self.ptr = src[].unsafe_uint8_ptr() - - fn __next__(inout self) -> StringSlice[mutability, lifetime]: - # Number of bytes of the current character - var char_length = int( - (DTypePointer[DType.uint8](self.ptr).load() >> 7 == 0).cast[DType.uint8]() * 1 - + countl_zero(~DTypePointer[DType.uint8](self.ptr).load()) - ) - - # Move iterator forward - self.bytes_left -= char_length - self.ptr += char_length - - return StringSlice[mutability, lifetime](unsafe_from_utf8_ptr=self.ptr - char_length, len=char_length) - - @always_inline - fn __len__(self) -> Int: - return self.bytes_left diff --git a/external/gojo/unicode/utf8/table.mojo b/external/gojo/unicode/utf8/table.mojo deleted file mode 100644 index 32717af..0000000 --- a/external/gojo/unicode/utf8/table.mojo +++ /dev/null @@ -1,1296 +0,0 @@ -@register_passable("trivial") -struct Interval: - var first: UInt32 - var last: UInt32 - - fn __init__(inout self, first: UInt32, last: UInt32): - self.first = first - self.last = last - - -alias combining = List[Interval]( - Interval(0x0300, 0x036F), - Interval(0x0483, 0x0489), - Interval(0x07EB, 0x07F3), - Interval(0x0C00, 0x0C00), - Interval(0x0C04, 0x0C04), - Interval(0x0D00, 0x0D01), - Interval(0x135D, 0x135F), - Interval(0x1A7F, 0x1A7F), - Interval(0x1AB0, 0x1AC0), - Interval(0x1B6B, 0x1B73), - Interval(0x1DC0, 0x1DF9), - Interval(0x1DFB, 0x1DFF), - Interval(0x20D0, 0x20F0), - Interval(0x2CEF, 0x2CF1), - Interval(0x2DE0, 0x2DFF), - Interval(0x3099, 0x309A), - Interval(0xA66F, 0xA672), - Interval(0xA674, 0xA67D), - Interval(0xA69E, 0xA69F), - Interval(0xA6F0, 0xA6F1), - Interval(0xA8E0, 0xA8F1), - Interval(0xFE20, 0xFE2F), - Interval(0x101FD, 0x101FD), - Interval(0x10376, 0x1037A), - Interval(0x10EAB, 0x10EAC), - Interval(0x10F46, 0x10F50), - Interval(0x11300, 0x11301), - Interval(0x1133B, 0x1133C), - Interval(0x11366, 0x1136C), - Interval(0x11370, 0x11374), - Interval(0x16AF0, 0x16AF4), - Interval(0x1D165, 0x1D169), - Interval(0x1D16D, 0x1D172), - Interval(0x1D17B, 0x1D182), - Interval(0x1D185, 0x1D18B), - Interval(0x1D1AA, 0x1D1AD), - Interval(0x1D242, 0x1D244), - Interval(0x1E000, 0x1E006), - Interval(0x1E008, 0x1E018), - Interval(0x1E01B, 0x1E021), - Interval(0x1E023, 0x1E024), - Interval(0x1E026, 0x1E02A), - Interval(0x1E8D0, 0x1E8D6), -) - -alias doublewidth = List[Interval]( - Interval(0x1100, 0x115F), - Interval(0x231A, 0x231B), - Interval(0x2329, 0x232A), - Interval(0x23E9, 0x23EC), - Interval(0x23F0, 0x23F0), - Interval(0x23F3, 0x23F3), - Interval(0x25FD, 0x25FE), - Interval(0x2614, 0x2615), - Interval(0x2648, 0x2653), - Interval(0x267F, 0x267F), - Interval(0x2693, 0x2693), - Interval(0x26A1, 0x26A1), - Interval(0x26AA, 0x26AB), - Interval(0x26BD, 0x26BE), - Interval(0x26C4, 0x26C5), - Interval(0x26CE, 0x26CE), - Interval(0x26D4, 0x26D4), - Interval(0x26EA, 0x26EA), - Interval(0x26F2, 0x26F3), - Interval(0x26F5, 0x26F5), - Interval(0x26FA, 0x26FA), - Interval(0x26FD, 0x26FD), - Interval(0x2705, 0x2705), - Interval(0x270A, 0x270B), - Interval(0x2728, 0x2728), - Interval(0x274C, 0x274C), - Interval(0x274E, 0x274E), - Interval(0x2753, 0x2755), - Interval(0x2757, 0x2757), - Interval(0x2795, 0x2797), - Interval(0x27B0, 0x27B0), - Interval(0x27BF, 0x27BF), - Interval(0x2B1B, 0x2B1C), - Interval(0x2B50, 0x2B50), - Interval(0x2B55, 0x2B55), - Interval(0x2E80, 0x2E99), - Interval(0x2E9B, 0x2EF3), - Interval(0x2F00, 0x2FD5), - Interval(0x2FF0, 0x2FFB), - Interval(0x3000, 0x303E), - Interval(0x3041, 0x3096), - Interval(0x3099, 0x30FF), - Interval(0x3105, 0x312F), - Interval(0x3131, 0x318E), - Interval(0x3190, 0x31E3), - Interval(0x31F0, 0x321E), - Interval(0x3220, 0x3247), - Interval(0x3250, 0x4DBF), - Interval(0x4E00, 0xA48C), - Interval(0xA490, 0xA4C6), - Interval(0xA960, 0xA97C), - Interval(0xAC00, 0xD7A3), - Interval(0xF900, 0xFAFF), - Interval(0xFE10, 0xFE19), - Interval(0xFE30, 0xFE52), - Interval(0xFE54, 0xFE66), - Interval(0xFE68, 0xFE6B), - Interval(0xFF01, 0xFF60), - Interval(0xFFE0, 0xFFE6), - Interval(0x16FE0, 0x16FE4), - Interval(0x16FF0, 0x16FF1), - Interval(0x17000, 0x187F7), - Interval(0x18800, 0x18CD5), - Interval(0x18D00, 0x18D08), - Interval(0x1B000, 0x1B11E), - Interval(0x1B150, 0x1B152), - Interval(0x1B164, 0x1B167), - Interval(0x1B170, 0x1B2FB), - Interval(0x1F004, 0x1F004), - Interval(0x1F0CF, 0x1F0CF), - Interval(0x1F18E, 0x1F18E), - Interval(0x1F191, 0x1F19A), - Interval(0x1F200, 0x1F202), - Interval(0x1F210, 0x1F23B), - Interval(0x1F240, 0x1F248), - Interval(0x1F250, 0x1F251), - Interval(0x1F260, 0x1F265), - Interval(0x1F300, 0x1F320), - Interval(0x1F32D, 0x1F335), - Interval(0x1F337, 0x1F37C), - Interval(0x1F37E, 0x1F393), - Interval(0x1F3A0, 0x1F3CA), - Interval(0x1F3CF, 0x1F3D3), - Interval(0x1F3E0, 0x1F3F0), - Interval(0x1F3F4, 0x1F3F4), - Interval(0x1F3F8, 0x1F43E), - Interval(0x1F440, 0x1F440), - Interval(0x1F442, 0x1F4FC), - Interval(0x1F4FF, 0x1F53D), - Interval(0x1F54B, 0x1F54E), - Interval(0x1F550, 0x1F567), - Interval(0x1F57A, 0x1F57A), - Interval(0x1F595, 0x1F596), - Interval(0x1F5A4, 0x1F5A4), - Interval(0x1F5FB, 0x1F64F), - Interval(0x1F680, 0x1F6C5), - Interval(0x1F6CC, 0x1F6CC), - Interval(0x1F6D0, 0x1F6D2), - Interval(0x1F6D5, 0x1F6D7), - Interval(0x1F6EB, 0x1F6EC), - Interval(0x1F6F4, 0x1F6FC), - Interval(0x1F7E0, 0x1F7EB), - Interval(0x1F90C, 0x1F93A), - Interval(0x1F93C, 0x1F945), - Interval(0x1F947, 0x1F978), - Interval(0x1F97A, 0x1F9CB), - Interval(0x1F9CD, 0x1F9FF), - Interval(0x1FA70, 0x1FA74), - Interval(0x1FA78, 0x1FA7A), - Interval(0x1FA80, 0x1FA86), - Interval(0x1FA90, 0x1FAA8), - Interval(0x1FAB0, 0x1FAB6), - Interval(0x1FAC0, 0x1FAC2), - Interval(0x1FAD0, 0x1FAD6), - Interval(0x20000, 0x2FFFD), - Interval(0x30000, 0x3FFFD), -) - -alias ambiguous = List[Interval]( - Interval(0x00A1, 0x00A1), - Interval(0x00A4, 0x00A4), - Interval(0x00A7, 0x00A8), - Interval(0x00AA, 0x00AA), - Interval(0x00AD, 0x00AE), - Interval(0x00B0, 0x00B4), - Interval(0x00B6, 0x00BA), - Interval(0x00BC, 0x00BF), - Interval(0x00C6, 0x00C6), - Interval(0x00D0, 0x00D0), - Interval(0x00D7, 0x00D8), - Interval(0x00DE, 0x00E1), - Interval(0x00E6, 0x00E6), - Interval(0x00E8, 0x00EA), - Interval(0x00EC, 0x00ED), - Interval(0x00F0, 0x00F0), - Interval(0x00F2, 0x00F3), - Interval(0x00F7, 0x00FA), - Interval(0x00FC, 0x00FC), - Interval(0x00FE, 0x00FE), - Interval(0x0101, 0x0101), - Interval(0x0111, 0x0111), - Interval(0x0113, 0x0113), - Interval(0x011B, 0x011B), - Interval(0x0126, 0x0127), - Interval(0x012B, 0x012B), - Interval(0x0131, 0x0133), - Interval(0x0138, 0x0138), - Interval(0x013F, 0x0142), - Interval(0x0144, 0x0144), - Interval(0x0148, 0x014B), - Interval(0x014D, 0x014D), - Interval(0x0152, 0x0153), - Interval(0x0166, 0x0167), - Interval(0x016B, 0x016B), - Interval(0x01CE, 0x01CE), - Interval(0x01D0, 0x01D0), - Interval(0x01D2, 0x01D2), - Interval(0x01D4, 0x01D4), - Interval(0x01D6, 0x01D6), - Interval(0x01D8, 0x01D8), - Interval(0x01DA, 0x01DA), - Interval(0x01DC, 0x01DC), - Interval(0x0251, 0x0251), - Interval(0x0261, 0x0261), - Interval(0x02C4, 0x02C4), - Interval(0x02C7, 0x02C7), - Interval(0x02C9, 0x02CB), - Interval(0x02CD, 0x02CD), - Interval(0x02D0, 0x02D0), - Interval(0x02D8, 0x02DB), - Interval(0x02DD, 0x02DD), - Interval(0x02DF, 0x02DF), - Interval(0x0300, 0x036F), - Interval(0x0391, 0x03A1), - Interval(0x03A3, 0x03A9), - Interval(0x03B1, 0x03C1), - Interval(0x03C3, 0x03C9), - Interval(0x0401, 0x0401), - Interval(0x0410, 0x044F), - Interval(0x0451, 0x0451), - Interval(0x2010, 0x2010), - Interval(0x2013, 0x2016), - Interval(0x2018, 0x2019), - Interval(0x201C, 0x201D), - Interval(0x2020, 0x2022), - Interval(0x2024, 0x2027), - Interval(0x2030, 0x2030), - Interval(0x2032, 0x2033), - Interval(0x2035, 0x2035), - Interval(0x203B, 0x203B), - Interval(0x203E, 0x203E), - Interval(0x2074, 0x2074), - Interval(0x207F, 0x207F), - Interval(0x2081, 0x2084), - Interval(0x20AC, 0x20AC), - Interval(0x2103, 0x2103), - Interval(0x2105, 0x2105), - Interval(0x2109, 0x2109), - Interval(0x2113, 0x2113), - Interval(0x2116, 0x2116), - Interval(0x2121, 0x2122), - Interval(0x2126, 0x2126), - Interval(0x212B, 0x212B), - Interval(0x2153, 0x2154), - Interval(0x215B, 0x215E), - Interval(0x2160, 0x216B), - Interval(0x2170, 0x2179), - Interval(0x2189, 0x2189), - Interval(0x2190, 0x2199), - Interval(0x21B8, 0x21B9), - Interval(0x21D2, 0x21D2), - Interval(0x21D4, 0x21D4), - Interval(0x21E7, 0x21E7), - Interval(0x2200, 0x2200), - Interval(0x2202, 0x2203), - Interval(0x2207, 0x2208), - Interval(0x220B, 0x220B), - Interval(0x220F, 0x220F), - Interval(0x2211, 0x2211), - Interval(0x2215, 0x2215), - Interval(0x221A, 0x221A), - Interval(0x221D, 0x2220), - Interval(0x2223, 0x2223), - Interval(0x2225, 0x2225), - Interval(0x2227, 0x222C), - Interval(0x222E, 0x222E), - Interval(0x2234, 0x2237), - Interval(0x223C, 0x223D), - Interval(0x2248, 0x2248), - Interval(0x224C, 0x224C), - Interval(0x2252, 0x2252), - Interval(0x2260, 0x2261), - Interval(0x2264, 0x2267), - Interval(0x226A, 0x226B), - Interval(0x226E, 0x226F), - Interval(0x2282, 0x2283), - Interval(0x2286, 0x2287), - Interval(0x2295, 0x2295), - Interval(0x2299, 0x2299), - Interval(0x22A5, 0x22A5), - Interval(0x22BF, 0x22BF), - Interval(0x2312, 0x2312), - Interval(0x2460, 0x24E9), - Interval(0x24EB, 0x254B), - Interval(0x2550, 0x2573), - Interval(0x2580, 0x258F), - Interval(0x2592, 0x2595), - Interval(0x25A0, 0x25A1), - Interval(0x25A3, 0x25A9), - Interval(0x25B2, 0x25B3), - Interval(0x25B6, 0x25B7), - Interval(0x25BC, 0x25BD), - Interval(0x25C0, 0x25C1), - Interval(0x25C6, 0x25C8), - Interval(0x25CB, 0x25CB), - Interval(0x25CE, 0x25D1), - Interval(0x25E2, 0x25E5), - Interval(0x25EF, 0x25EF), - Interval(0x2605, 0x2606), - Interval(0x2609, 0x2609), - Interval(0x260E, 0x260F), - Interval(0x261C, 0x261C), - Interval(0x261E, 0x261E), - Interval(0x2640, 0x2640), - Interval(0x2642, 0x2642), - Interval(0x2660, 0x2661), - Interval(0x2663, 0x2665), - Interval(0x2667, 0x266A), - Interval(0x266C, 0x266D), - Interval(0x266F, 0x266F), - Interval(0x269E, 0x269F), - Interval(0x26BF, 0x26BF), - Interval(0x26C6, 0x26CD), - Interval(0x26CF, 0x26D3), - Interval(0x26D5, 0x26E1), - Interval(0x26E3, 0x26E3), - Interval(0x26E8, 0x26E9), - Interval(0x26EB, 0x26F1), - Interval(0x26F4, 0x26F4), - Interval(0x26F6, 0x26F9), - Interval(0x26FB, 0x26FC), - Interval(0x26FE, 0x26FF), - Interval(0x273D, 0x273D), - Interval(0x2776, 0x277F), - Interval(0x2B56, 0x2B59), - Interval(0x3248, 0x324F), - Interval(0xE000, 0xF8FF), - Interval(0xFE00, 0xFE0F), - Interval(0xFFFD, 0xFFFD), - Interval(0x1F100, 0x1F10A), - Interval(0x1F110, 0x1F12D), - Interval(0x1F130, 0x1F169), - Interval(0x1F170, 0x1F18D), - Interval(0x1F18F, 0x1F190), - Interval(0x1F19B, 0x1F1AC), - Interval(0xE0100, 0xE01EF), - Interval(0xF0000, 0xFFFFD), - Interval(0x100000, 0x10FFFD), -) - -alias narrow = List[Interval]( - Interval(0x0020, 0x007E), - Interval(0x00A2, 0x00A3), - Interval(0x00A5, 0x00A6), - Interval(0x00AC, 0x00AC), - Interval(0x00AF, 0x00AF), - Interval(0x27E6, 0x27ED), - Interval(0x2985, 0x2986), -) - -alias neutral = List[Interval]( - Interval(0x0000, 0x001F), - Interval(0x007F, 0x00A0), - Interval(0x00A9, 0x00A9), - Interval(0x00AB, 0x00AB), - Interval(0x00B5, 0x00B5), - Interval(0x00BB, 0x00BB), - Interval(0x00C0, 0x00C5), - Interval(0x00C7, 0x00CF), - Interval(0x00D1, 0x00D6), - Interval(0x00D9, 0x00DD), - Interval(0x00E2, 0x00E5), - Interval(0x00E7, 0x00E7), - Interval(0x00EB, 0x00EB), - Interval(0x00EE, 0x00EF), - Interval(0x00F1, 0x00F1), - Interval(0x00F4, 0x00F6), - Interval(0x00FB, 0x00FB), - Interval(0x00FD, 0x00FD), - Interval(0x00FF, 0x0100), - Interval(0x0102, 0x0110), - Interval(0x0112, 0x0112), - Interval(0x0114, 0x011A), - Interval(0x011C, 0x0125), - Interval(0x0128, 0x012A), - Interval(0x012C, 0x0130), - Interval(0x0134, 0x0137), - Interval(0x0139, 0x013E), - Interval(0x0143, 0x0143), - Interval(0x0145, 0x0147), - Interval(0x014C, 0x014C), - Interval(0x014E, 0x0151), - Interval(0x0154, 0x0165), - Interval(0x0168, 0x016A), - Interval(0x016C, 0x01CD), - Interval(0x01CF, 0x01CF), - Interval(0x01D1, 0x01D1), - Interval(0x01D3, 0x01D3), - Interval(0x01D5, 0x01D5), - Interval(0x01D7, 0x01D7), - Interval(0x01D9, 0x01D9), - Interval(0x01DB, 0x01DB), - Interval(0x01DD, 0x0250), - Interval(0x0252, 0x0260), - Interval(0x0262, 0x02C3), - Interval(0x02C5, 0x02C6), - Interval(0x02C8, 0x02C8), - Interval(0x02CC, 0x02CC), - Interval(0x02CE, 0x02CF), - Interval(0x02D1, 0x02D7), - Interval(0x02DC, 0x02DC), - Interval(0x02DE, 0x02DE), - Interval(0x02E0, 0x02FF), - Interval(0x0370, 0x0377), - Interval(0x037A, 0x037F), - Interval(0x0384, 0x038A), - Interval(0x038C, 0x038C), - Interval(0x038E, 0x0390), - Interval(0x03AA, 0x03B0), - Interval(0x03C2, 0x03C2), - Interval(0x03CA, 0x0400), - Interval(0x0402, 0x040F), - Interval(0x0450, 0x0450), - Interval(0x0452, 0x052F), - Interval(0x0531, 0x0556), - Interval(0x0559, 0x058A), - Interval(0x058D, 0x058F), - Interval(0x0591, 0x05C7), - Interval(0x05D0, 0x05EA), - Interval(0x05EF, 0x05F4), - Interval(0x0600, 0x061C), - Interval(0x061E, 0x070D), - Interval(0x070F, 0x074A), - Interval(0x074D, 0x07B1), - Interval(0x07C0, 0x07FA), - Interval(0x07FD, 0x082D), - Interval(0x0830, 0x083E), - Interval(0x0840, 0x085B), - Interval(0x085E, 0x085E), - Interval(0x0860, 0x086A), - Interval(0x08A0, 0x08B4), - Interval(0x08B6, 0x08C7), - Interval(0x08D3, 0x0983), - Interval(0x0985, 0x098C), - Interval(0x098F, 0x0990), - Interval(0x0993, 0x09A8), - Interval(0x09AA, 0x09B0), - Interval(0x09B2, 0x09B2), - Interval(0x09B6, 0x09B9), - Interval(0x09BC, 0x09C4), - Interval(0x09C7, 0x09C8), - Interval(0x09CB, 0x09CE), - Interval(0x09D7, 0x09D7), - Interval(0x09DC, 0x09DD), - Interval(0x09DF, 0x09E3), - Interval(0x09E6, 0x09FE), - Interval(0x0A01, 0x0A03), - Interval(0x0A05, 0x0A0A), - Interval(0x0A0F, 0x0A10), - Interval(0x0A13, 0x0A28), - Interval(0x0A2A, 0x0A30), - Interval(0x0A32, 0x0A33), - Interval(0x0A35, 0x0A36), - Interval(0x0A38, 0x0A39), - Interval(0x0A3C, 0x0A3C), - Interval(0x0A3E, 0x0A42), - Interval(0x0A47, 0x0A48), - Interval(0x0A4B, 0x0A4D), - Interval(0x0A51, 0x0A51), - Interval(0x0A59, 0x0A5C), - Interval(0x0A5E, 0x0A5E), - Interval(0x0A66, 0x0A76), - Interval(0x0A81, 0x0A83), - Interval(0x0A85, 0x0A8D), - Interval(0x0A8F, 0x0A91), - Interval(0x0A93, 0x0AA8), - Interval(0x0AAA, 0x0AB0), - Interval(0x0AB2, 0x0AB3), - Interval(0x0AB5, 0x0AB9), - Interval(0x0ABC, 0x0AC5), - Interval(0x0AC7, 0x0AC9), - Interval(0x0ACB, 0x0ACD), - Interval(0x0AD0, 0x0AD0), - Interval(0x0AE0, 0x0AE3), - Interval(0x0AE6, 0x0AF1), - Interval(0x0AF9, 0x0AFF), - Interval(0x0B01, 0x0B03), - Interval(0x0B05, 0x0B0C), - Interval(0x0B0F, 0x0B10), - Interval(0x0B13, 0x0B28), - Interval(0x0B2A, 0x0B30), - Interval(0x0B32, 0x0B33), - Interval(0x0B35, 0x0B39), - Interval(0x0B3C, 0x0B44), - Interval(0x0B47, 0x0B48), - Interval(0x0B4B, 0x0B4D), - Interval(0x0B55, 0x0B57), - Interval(0x0B5C, 0x0B5D), - Interval(0x0B5F, 0x0B63), - Interval(0x0B66, 0x0B77), - Interval(0x0B82, 0x0B83), - Interval(0x0B85, 0x0B8A), - Interval(0x0B8E, 0x0B90), - Interval(0x0B92, 0x0B95), - Interval(0x0B99, 0x0B9A), - Interval(0x0B9C, 0x0B9C), - Interval(0x0B9E, 0x0B9F), - Interval(0x0BA3, 0x0BA4), - Interval(0x0BA8, 0x0BAA), - Interval(0x0BAE, 0x0BB9), - Interval(0x0BBE, 0x0BC2), - Interval(0x0BC6, 0x0BC8), - Interval(0x0BCA, 0x0BCD), - Interval(0x0BD0, 0x0BD0), - Interval(0x0BD7, 0x0BD7), - Interval(0x0BE6, 0x0BFA), - Interval(0x0C00, 0x0C0C), - Interval(0x0C0E, 0x0C10), - Interval(0x0C12, 0x0C28), - Interval(0x0C2A, 0x0C39), - Interval(0x0C3D, 0x0C44), - Interval(0x0C46, 0x0C48), - Interval(0x0C4A, 0x0C4D), - Interval(0x0C55, 0x0C56), - Interval(0x0C58, 0x0C5A), - Interval(0x0C60, 0x0C63), - Interval(0x0C66, 0x0C6F), - Interval(0x0C77, 0x0C8C), - Interval(0x0C8E, 0x0C90), - Interval(0x0C92, 0x0CA8), - Interval(0x0CAA, 0x0CB3), - Interval(0x0CB5, 0x0CB9), - Interval(0x0CBC, 0x0CC4), - Interval(0x0CC6, 0x0CC8), - Interval(0x0CCA, 0x0CCD), - Interval(0x0CD5, 0x0CD6), - Interval(0x0CDE, 0x0CDE), - Interval(0x0CE0, 0x0CE3), - Interval(0x0CE6, 0x0CEF), - Interval(0x0CF1, 0x0CF2), - Interval(0x0D00, 0x0D0C), - Interval(0x0D0E, 0x0D10), - Interval(0x0D12, 0x0D44), - Interval(0x0D46, 0x0D48), - Interval(0x0D4A, 0x0D4F), - Interval(0x0D54, 0x0D63), - Interval(0x0D66, 0x0D7F), - Interval(0x0D81, 0x0D83), - Interval(0x0D85, 0x0D96), - Interval(0x0D9A, 0x0DB1), - Interval(0x0DB3, 0x0DBB), - Interval(0x0DBD, 0x0DBD), - Interval(0x0DC0, 0x0DC6), - Interval(0x0DCA, 0x0DCA), - Interval(0x0DCF, 0x0DD4), - Interval(0x0DD6, 0x0DD6), - Interval(0x0DD8, 0x0DDF), - Interval(0x0DE6, 0x0DEF), - Interval(0x0DF2, 0x0DF4), - Interval(0x0E01, 0x0E3A), - Interval(0x0E3F, 0x0E5B), - Interval(0x0E81, 0x0E82), - Interval(0x0E84, 0x0E84), - Interval(0x0E86, 0x0E8A), - Interval(0x0E8C, 0x0EA3), - Interval(0x0EA5, 0x0EA5), - Interval(0x0EA7, 0x0EBD), - Interval(0x0EC0, 0x0EC4), - Interval(0x0EC6, 0x0EC6), - Interval(0x0EC8, 0x0ECD), - Interval(0x0ED0, 0x0ED9), - Interval(0x0EDC, 0x0EDF), - Interval(0x0F00, 0x0F47), - Interval(0x0F49, 0x0F6C), - Interval(0x0F71, 0x0F97), - Interval(0x0F99, 0x0FBC), - Interval(0x0FBE, 0x0FCC), - Interval(0x0FCE, 0x0FDA), - Interval(0x1000, 0x10C5), - Interval(0x10C7, 0x10C7), - Interval(0x10CD, 0x10CD), - Interval(0x10D0, 0x10FF), - Interval(0x1160, 0x1248), - Interval(0x124A, 0x124D), - Interval(0x1250, 0x1256), - Interval(0x1258, 0x1258), - Interval(0x125A, 0x125D), - Interval(0x1260, 0x1288), - Interval(0x128A, 0x128D), - Interval(0x1290, 0x12B0), - Interval(0x12B2, 0x12B5), - Interval(0x12B8, 0x12BE), - Interval(0x12C0, 0x12C0), - Interval(0x12C2, 0x12C5), - Interval(0x12C8, 0x12D6), - Interval(0x12D8, 0x1310), - Interval(0x1312, 0x1315), - Interval(0x1318, 0x135A), - Interval(0x135D, 0x137C), - Interval(0x1380, 0x1399), - Interval(0x13A0, 0x13F5), - Interval(0x13F8, 0x13FD), - Interval(0x1400, 0x169C), - Interval(0x16A0, 0x16F8), - Interval(0x1700, 0x170C), - Interval(0x170E, 0x1714), - Interval(0x1720, 0x1736), - Interval(0x1740, 0x1753), - Interval(0x1760, 0x176C), - Interval(0x176E, 0x1770), - Interval(0x1772, 0x1773), - Interval(0x1780, 0x17DD), - Interval(0x17E0, 0x17E9), - Interval(0x17F0, 0x17F9), - Interval(0x1800, 0x180E), - Interval(0x1810, 0x1819), - Interval(0x1820, 0x1878), - Interval(0x1880, 0x18AA), - Interval(0x18B0, 0x18F5), - Interval(0x1900, 0x191E), - Interval(0x1920, 0x192B), - Interval(0x1930, 0x193B), - Interval(0x1940, 0x1940), - Interval(0x1944, 0x196D), - Interval(0x1970, 0x1974), - Interval(0x1980, 0x19AB), - Interval(0x19B0, 0x19C9), - Interval(0x19D0, 0x19DA), - Interval(0x19DE, 0x1A1B), - Interval(0x1A1E, 0x1A5E), - Interval(0x1A60, 0x1A7C), - Interval(0x1A7F, 0x1A89), - Interval(0x1A90, 0x1A99), - Interval(0x1AA0, 0x1AAD), - Interval(0x1AB0, 0x1AC0), - Interval(0x1B00, 0x1B4B), - Interval(0x1B50, 0x1B7C), - Interval(0x1B80, 0x1BF3), - Interval(0x1BFC, 0x1C37), - Interval(0x1C3B, 0x1C49), - Interval(0x1C4D, 0x1C88), - Interval(0x1C90, 0x1CBA), - Interval(0x1CBD, 0x1CC7), - Interval(0x1CD0, 0x1CFA), - Interval(0x1D00, 0x1DF9), - Interval(0x1DFB, 0x1F15), - Interval(0x1F18, 0x1F1D), - Interval(0x1F20, 0x1F45), - Interval(0x1F48, 0x1F4D), - Interval(0x1F50, 0x1F57), - Interval(0x1F59, 0x1F59), - Interval(0x1F5B, 0x1F5B), - Interval(0x1F5D, 0x1F5D), - Interval(0x1F5F, 0x1F7D), - Interval(0x1F80, 0x1FB4), - Interval(0x1FB6, 0x1FC4), - Interval(0x1FC6, 0x1FD3), - Interval(0x1FD6, 0x1FDB), - Interval(0x1FDD, 0x1FEF), - Interval(0x1FF2, 0x1FF4), - Interval(0x1FF6, 0x1FFE), - Interval(0x2000, 0x200F), - Interval(0x2011, 0x2012), - Interval(0x2017, 0x2017), - Interval(0x201A, 0x201B), - Interval(0x201E, 0x201F), - Interval(0x2023, 0x2023), - Interval(0x2028, 0x202F), - Interval(0x2031, 0x2031), - Interval(0x2034, 0x2034), - Interval(0x2036, 0x203A), - Interval(0x203C, 0x203D), - Interval(0x203F, 0x2064), - Interval(0x2066, 0x2071), - Interval(0x2075, 0x207E), - Interval(0x2080, 0x2080), - Interval(0x2085, 0x208E), - Interval(0x2090, 0x209C), - Interval(0x20A0, 0x20A8), - Interval(0x20AA, 0x20AB), - Interval(0x20AD, 0x20BF), - Interval(0x20D0, 0x20F0), - Interval(0x2100, 0x2102), - Interval(0x2104, 0x2104), - Interval(0x2106, 0x2108), - Interval(0x210A, 0x2112), - Interval(0x2114, 0x2115), - Interval(0x2117, 0x2120), - Interval(0x2123, 0x2125), - Interval(0x2127, 0x212A), - Interval(0x212C, 0x2152), - Interval(0x2155, 0x215A), - Interval(0x215F, 0x215F), - Interval(0x216C, 0x216F), - Interval(0x217A, 0x2188), - Interval(0x218A, 0x218B), - Interval(0x219A, 0x21B7), - Interval(0x21BA, 0x21D1), - Interval(0x21D3, 0x21D3), - Interval(0x21D5, 0x21E6), - Interval(0x21E8, 0x21FF), - Interval(0x2201, 0x2201), - Interval(0x2204, 0x2206), - Interval(0x2209, 0x220A), - Interval(0x220C, 0x220E), - Interval(0x2210, 0x2210), - Interval(0x2212, 0x2214), - Interval(0x2216, 0x2219), - Interval(0x221B, 0x221C), - Interval(0x2221, 0x2222), - Interval(0x2224, 0x2224), - Interval(0x2226, 0x2226), - Interval(0x222D, 0x222D), - Interval(0x222F, 0x2233), - Interval(0x2238, 0x223B), - Interval(0x223E, 0x2247), - Interval(0x2249, 0x224B), - Interval(0x224D, 0x2251), - Interval(0x2253, 0x225F), - Interval(0x2262, 0x2263), - Interval(0x2268, 0x2269), - Interval(0x226C, 0x226D), - Interval(0x2270, 0x2281), - Interval(0x2284, 0x2285), - Interval(0x2288, 0x2294), - Interval(0x2296, 0x2298), - Interval(0x229A, 0x22A4), - Interval(0x22A6, 0x22BE), - Interval(0x22C0, 0x2311), - Interval(0x2313, 0x2319), - Interval(0x231C, 0x2328), - Interval(0x232B, 0x23E8), - Interval(0x23ED, 0x23EF), - Interval(0x23F1, 0x23F2), - Interval(0x23F4, 0x2426), - Interval(0x2440, 0x244A), - Interval(0x24EA, 0x24EA), - Interval(0x254C, 0x254F), - Interval(0x2574, 0x257F), - Interval(0x2590, 0x2591), - Interval(0x2596, 0x259F), - Interval(0x25A2, 0x25A2), - Interval(0x25AA, 0x25B1), - Interval(0x25B4, 0x25B5), - Interval(0x25B8, 0x25BB), - Interval(0x25BE, 0x25BF), - Interval(0x25C2, 0x25C5), - Interval(0x25C9, 0x25CA), - Interval(0x25CC, 0x25CD), - Interval(0x25D2, 0x25E1), - Interval(0x25E6, 0x25EE), - Interval(0x25F0, 0x25FC), - Interval(0x25FF, 0x2604), - Interval(0x2607, 0x2608), - Interval(0x260A, 0x260D), - Interval(0x2610, 0x2613), - Interval(0x2616, 0x261B), - Interval(0x261D, 0x261D), - Interval(0x261F, 0x263F), - Interval(0x2641, 0x2641), - Interval(0x2643, 0x2647), - Interval(0x2654, 0x265F), - Interval(0x2662, 0x2662), - Interval(0x2666, 0x2666), - Interval(0x266B, 0x266B), - Interval(0x266E, 0x266E), - Interval(0x2670, 0x267E), - Interval(0x2680, 0x2692), - Interval(0x2694, 0x269D), - Interval(0x26A0, 0x26A0), - Interval(0x26A2, 0x26A9), - Interval(0x26AC, 0x26BC), - Interval(0x26C0, 0x26C3), - Interval(0x26E2, 0x26E2), - Interval(0x26E4, 0x26E7), - Interval(0x2700, 0x2704), - Interval(0x2706, 0x2709), - Interval(0x270C, 0x2727), - Interval(0x2729, 0x273C), - Interval(0x273E, 0x274B), - Interval(0x274D, 0x274D), - Interval(0x274F, 0x2752), - Interval(0x2756, 0x2756), - Interval(0x2758, 0x2775), - Interval(0x2780, 0x2794), - Interval(0x2798, 0x27AF), - Interval(0x27B1, 0x27BE), - Interval(0x27C0, 0x27E5), - Interval(0x27EE, 0x2984), - Interval(0x2987, 0x2B1A), - Interval(0x2B1D, 0x2B4F), - Interval(0x2B51, 0x2B54), - Interval(0x2B5A, 0x2B73), - Interval(0x2B76, 0x2B95), - Interval(0x2B97, 0x2C2E), - Interval(0x2C30, 0x2C5E), - Interval(0x2C60, 0x2CF3), - Interval(0x2CF9, 0x2D25), - Interval(0x2D27, 0x2D27), - Interval(0x2D2D, 0x2D2D), - Interval(0x2D30, 0x2D67), - Interval(0x2D6F, 0x2D70), - Interval(0x2D7F, 0x2D96), - Interval(0x2DA0, 0x2DA6), - Interval(0x2DA8, 0x2DAE), - Interval(0x2DB0, 0x2DB6), - Interval(0x2DB8, 0x2DBE), - Interval(0x2DC0, 0x2DC6), - Interval(0x2DC8, 0x2DCE), - Interval(0x2DD0, 0x2DD6), - Interval(0x2DD8, 0x2DDE), - Interval(0x2DE0, 0x2E52), - Interval(0x303F, 0x303F), - Interval(0x4DC0, 0x4DFF), - Interval(0xA4D0, 0xA62B), - Interval(0xA640, 0xA6F7), - Interval(0xA700, 0xA7BF), - Interval(0xA7C2, 0xA7CA), - Interval(0xA7F5, 0xA82C), - Interval(0xA830, 0xA839), - Interval(0xA840, 0xA877), - Interval(0xA880, 0xA8C5), - Interval(0xA8CE, 0xA8D9), - Interval(0xA8E0, 0xA953), - Interval(0xA95F, 0xA95F), - Interval(0xA980, 0xA9CD), - Interval(0xA9CF, 0xA9D9), - Interval(0xA9DE, 0xA9FE), - Interval(0xAA00, 0xAA36), - Interval(0xAA40, 0xAA4D), - Interval(0xAA50, 0xAA59), - Interval(0xAA5C, 0xAAC2), - Interval(0xAADB, 0xAAF6), - Interval(0xAB01, 0xAB06), - Interval(0xAB09, 0xAB0E), - Interval(0xAB11, 0xAB16), - Interval(0xAB20, 0xAB26), - Interval(0xAB28, 0xAB2E), - Interval(0xAB30, 0xAB6B), - Interval(0xAB70, 0xABED), - Interval(0xABF0, 0xABF9), - Interval(0xD7B0, 0xD7C6), - Interval(0xD7CB, 0xD7FB), - Interval(0xD800, 0xDFFF), - Interval(0xFB00, 0xFB06), - Interval(0xFB13, 0xFB17), - Interval(0xFB1D, 0xFB36), - Interval(0xFB38, 0xFB3C), - Interval(0xFB3E, 0xFB3E), - Interval(0xFB40, 0xFB41), - Interval(0xFB43, 0xFB44), - Interval(0xFB46, 0xFBC1), - Interval(0xFBD3, 0xFD3F), - Interval(0xFD50, 0xFD8F), - Interval(0xFD92, 0xFDC7), - Interval(0xFDF0, 0xFDFD), - Interval(0xFE20, 0xFE2F), - Interval(0xFE70, 0xFE74), - Interval(0xFE76, 0xFEFC), - Interval(0xFEFF, 0xFEFF), - Interval(0xFFF9, 0xFFFC), - Interval(0x10000, 0x1000B), - Interval(0x1000D, 0x10026), - Interval(0x10028, 0x1003A), - Interval(0x1003C, 0x1003D), - Interval(0x1003F, 0x1004D), - Interval(0x10050, 0x1005D), - Interval(0x10080, 0x100FA), - Interval(0x10100, 0x10102), - Interval(0x10107, 0x10133), - Interval(0x10137, 0x1018E), - Interval(0x10190, 0x1019C), - Interval(0x101A0, 0x101A0), - Interval(0x101D0, 0x101FD), - Interval(0x10280, 0x1029C), - Interval(0x102A0, 0x102D0), - Interval(0x102E0, 0x102FB), - Interval(0x10300, 0x10323), - Interval(0x1032D, 0x1034A), - Interval(0x10350, 0x1037A), - Interval(0x10380, 0x1039D), - Interval(0x1039F, 0x103C3), - Interval(0x103C8, 0x103D5), - Interval(0x10400, 0x1049D), - Interval(0x104A0, 0x104A9), - Interval(0x104B0, 0x104D3), - Interval(0x104D8, 0x104FB), - Interval(0x10500, 0x10527), - Interval(0x10530, 0x10563), - Interval(0x1056F, 0x1056F), - Interval(0x10600, 0x10736), - Interval(0x10740, 0x10755), - Interval(0x10760, 0x10767), - Interval(0x10800, 0x10805), - Interval(0x10808, 0x10808), - Interval(0x1080A, 0x10835), - Interval(0x10837, 0x10838), - Interval(0x1083C, 0x1083C), - Interval(0x1083F, 0x10855), - Interval(0x10857, 0x1089E), - Interval(0x108A7, 0x108AF), - Interval(0x108E0, 0x108F2), - Interval(0x108F4, 0x108F5), - Interval(0x108FB, 0x1091B), - Interval(0x1091F, 0x10939), - Interval(0x1093F, 0x1093F), - Interval(0x10980, 0x109B7), - Interval(0x109BC, 0x109CF), - Interval(0x109D2, 0x10A03), - Interval(0x10A05, 0x10A06), - Interval(0x10A0C, 0x10A13), - Interval(0x10A15, 0x10A17), - Interval(0x10A19, 0x10A35), - Interval(0x10A38, 0x10A3A), - Interval(0x10A3F, 0x10A48), - Interval(0x10A50, 0x10A58), - Interval(0x10A60, 0x10A9F), - Interval(0x10AC0, 0x10AE6), - Interval(0x10AEB, 0x10AF6), - Interval(0x10B00, 0x10B35), - Interval(0x10B39, 0x10B55), - Interval(0x10B58, 0x10B72), - Interval(0x10B78, 0x10B91), - Interval(0x10B99, 0x10B9C), - Interval(0x10BA9, 0x10BAF), - Interval(0x10C00, 0x10C48), - Interval(0x10C80, 0x10CB2), - Interval(0x10CC0, 0x10CF2), - Interval(0x10CFA, 0x10D27), - Interval(0x10D30, 0x10D39), - Interval(0x10E60, 0x10E7E), - Interval(0x10E80, 0x10EA9), - Interval(0x10EAB, 0x10EAD), - Interval(0x10EB0, 0x10EB1), - Interval(0x10F00, 0x10F27), - Interval(0x10F30, 0x10F59), - Interval(0x10FB0, 0x10FCB), - Interval(0x10FE0, 0x10FF6), - Interval(0x11000, 0x1104D), - Interval(0x11052, 0x1106F), - Interval(0x1107F, 0x110C1), - Interval(0x110CD, 0x110CD), - Interval(0x110D0, 0x110E8), - Interval(0x110F0, 0x110F9), - Interval(0x11100, 0x11134), - Interval(0x11136, 0x11147), - Interval(0x11150, 0x11176), - Interval(0x11180, 0x111DF), - Interval(0x111E1, 0x111F4), - Interval(0x11200, 0x11211), - Interval(0x11213, 0x1123E), - Interval(0x11280, 0x11286), - Interval(0x11288, 0x11288), - Interval(0x1128A, 0x1128D), - Interval(0x1128F, 0x1129D), - Interval(0x1129F, 0x112A9), - Interval(0x112B0, 0x112EA), - Interval(0x112F0, 0x112F9), - Interval(0x11300, 0x11303), - Interval(0x11305, 0x1130C), - Interval(0x1130F, 0x11310), - Interval(0x11313, 0x11328), - Interval(0x1132A, 0x11330), - Interval(0x11332, 0x11333), - Interval(0x11335, 0x11339), - Interval(0x1133B, 0x11344), - Interval(0x11347, 0x11348), - Interval(0x1134B, 0x1134D), - Interval(0x11350, 0x11350), - Interval(0x11357, 0x11357), - Interval(0x1135D, 0x11363), - Interval(0x11366, 0x1136C), - Interval(0x11370, 0x11374), - Interval(0x11400, 0x1145B), - Interval(0x1145D, 0x11461), - Interval(0x11480, 0x114C7), - Interval(0x114D0, 0x114D9), - Interval(0x11580, 0x115B5), - Interval(0x115B8, 0x115DD), - Interval(0x11600, 0x11644), - Interval(0x11650, 0x11659), - Interval(0x11660, 0x1166C), - Interval(0x11680, 0x116B8), - Interval(0x116C0, 0x116C9), - Interval(0x11700, 0x1171A), - Interval(0x1171D, 0x1172B), - Interval(0x11730, 0x1173F), - Interval(0x11800, 0x1183B), - Interval(0x118A0, 0x118F2), - Interval(0x118FF, 0x11906), - Interval(0x11909, 0x11909), - Interval(0x1190C, 0x11913), - Interval(0x11915, 0x11916), - Interval(0x11918, 0x11935), - Interval(0x11937, 0x11938), - Interval(0x1193B, 0x11946), - Interval(0x11950, 0x11959), - Interval(0x119A0, 0x119A7), - Interval(0x119AA, 0x119D7), - Interval(0x119DA, 0x119E4), - Interval(0x11A00, 0x11A47), - Interval(0x11A50, 0x11AA2), - Interval(0x11AC0, 0x11AF8), - Interval(0x11C00, 0x11C08), - Interval(0x11C0A, 0x11C36), - Interval(0x11C38, 0x11C45), - Interval(0x11C50, 0x11C6C), - Interval(0x11C70, 0x11C8F), - Interval(0x11C92, 0x11CA7), - Interval(0x11CA9, 0x11CB6), - Interval(0x11D00, 0x11D06), - Interval(0x11D08, 0x11D09), - Interval(0x11D0B, 0x11D36), - Interval(0x11D3A, 0x11D3A), - Interval(0x11D3C, 0x11D3D), - Interval(0x11D3F, 0x11D47), - Interval(0x11D50, 0x11D59), - Interval(0x11D60, 0x11D65), - Interval(0x11D67, 0x11D68), - Interval(0x11D6A, 0x11D8E), - Interval(0x11D90, 0x11D91), - Interval(0x11D93, 0x11D98), - Interval(0x11DA0, 0x11DA9), - Interval(0x11EE0, 0x11EF8), - Interval(0x11FB0, 0x11FB0), - Interval(0x11FC0, 0x11FF1), - Interval(0x11FFF, 0x12399), - Interval(0x12400, 0x1246E), - Interval(0x12470, 0x12474), - Interval(0x12480, 0x12543), - Interval(0x13000, 0x1342E), - Interval(0x13430, 0x13438), - Interval(0x14400, 0x14646), - Interval(0x16800, 0x16A38), - Interval(0x16A40, 0x16A5E), - Interval(0x16A60, 0x16A69), - Interval(0x16A6E, 0x16A6F), - Interval(0x16AD0, 0x16AED), - Interval(0x16AF0, 0x16AF5), - Interval(0x16B00, 0x16B45), - Interval(0x16B50, 0x16B59), - Interval(0x16B5B, 0x16B61), - Interval(0x16B63, 0x16B77), - Interval(0x16B7D, 0x16B8F), - Interval(0x16E40, 0x16E9A), - Interval(0x16F00, 0x16F4A), - Interval(0x16F4F, 0x16F87), - Interval(0x16F8F, 0x16F9F), - Interval(0x1BC00, 0x1BC6A), - Interval(0x1BC70, 0x1BC7C), - Interval(0x1BC80, 0x1BC88), - Interval(0x1BC90, 0x1BC99), - Interval(0x1BC9C, 0x1BCA3), - Interval(0x1D000, 0x1D0F5), - Interval(0x1D100, 0x1D126), - Interval(0x1D129, 0x1D1E8), - Interval(0x1D200, 0x1D245), - Interval(0x1D2E0, 0x1D2F3), - Interval(0x1D300, 0x1D356), - Interval(0x1D360, 0x1D378), - Interval(0x1D400, 0x1D454), - Interval(0x1D456, 0x1D49C), - Interval(0x1D49E, 0x1D49F), - Interval(0x1D4A2, 0x1D4A2), - Interval(0x1D4A5, 0x1D4A6), - Interval(0x1D4A9, 0x1D4AC), - Interval(0x1D4AE, 0x1D4B9), - Interval(0x1D4BB, 0x1D4BB), - Interval(0x1D4BD, 0x1D4C3), - Interval(0x1D4C5, 0x1D505), - Interval(0x1D507, 0x1D50A), - Interval(0x1D50D, 0x1D514), - Interval(0x1D516, 0x1D51C), - Interval(0x1D51E, 0x1D539), - Interval(0x1D53B, 0x1D53E), - Interval(0x1D540, 0x1D544), - Interval(0x1D546, 0x1D546), - Interval(0x1D54A, 0x1D550), - Interval(0x1D552, 0x1D6A5), - Interval(0x1D6A8, 0x1D7CB), - Interval(0x1D7CE, 0x1DA8B), - Interval(0x1DA9B, 0x1DA9F), - Interval(0x1DAA1, 0x1DAAF), - Interval(0x1E000, 0x1E006), - Interval(0x1E008, 0x1E018), - Interval(0x1E01B, 0x1E021), - Interval(0x1E023, 0x1E024), - Interval(0x1E026, 0x1E02A), - Interval(0x1E100, 0x1E12C), - Interval(0x1E130, 0x1E13D), - Interval(0x1E140, 0x1E149), - Interval(0x1E14E, 0x1E14F), - Interval(0x1E2C0, 0x1E2F9), - Interval(0x1E2FF, 0x1E2FF), - Interval(0x1E800, 0x1E8C4), - Interval(0x1E8C7, 0x1E8D6), - Interval(0x1E900, 0x1E94B), - Interval(0x1E950, 0x1E959), - Interval(0x1E95E, 0x1E95F), - Interval(0x1EC71, 0x1ECB4), - Interval(0x1ED01, 0x1ED3D), - Interval(0x1EE00, 0x1EE03), - Interval(0x1EE05, 0x1EE1F), - Interval(0x1EE21, 0x1EE22), - Interval(0x1EE24, 0x1EE24), - Interval(0x1EE27, 0x1EE27), - Interval(0x1EE29, 0x1EE32), - Interval(0x1EE34, 0x1EE37), - Interval(0x1EE39, 0x1EE39), - Interval(0x1EE3B, 0x1EE3B), - Interval(0x1EE42, 0x1EE42), - Interval(0x1EE47, 0x1EE47), - Interval(0x1EE49, 0x1EE49), - Interval(0x1EE4B, 0x1EE4B), - Interval(0x1EE4D, 0x1EE4F), - Interval(0x1EE51, 0x1EE52), - Interval(0x1EE54, 0x1EE54), - Interval(0x1EE57, 0x1EE57), - Interval(0x1EE59, 0x1EE59), - Interval(0x1EE5B, 0x1EE5B), - Interval(0x1EE5D, 0x1EE5D), - Interval(0x1EE5F, 0x1EE5F), - Interval(0x1EE61, 0x1EE62), - Interval(0x1EE64, 0x1EE64), - Interval(0x1EE67, 0x1EE6A), - Interval(0x1EE6C, 0x1EE72), - Interval(0x1EE74, 0x1EE77), - Interval(0x1EE79, 0x1EE7C), - Interval(0x1EE7E, 0x1EE7E), - Interval(0x1EE80, 0x1EE89), - Interval(0x1EE8B, 0x1EE9B), - Interval(0x1EEA1, 0x1EEA3), - Interval(0x1EEA5, 0x1EEA9), - Interval(0x1EEAB, 0x1EEBB), - Interval(0x1EEF0, 0x1EEF1), - Interval(0x1F000, 0x1F003), - Interval(0x1F005, 0x1F02B), - Interval(0x1F030, 0x1F093), - Interval(0x1F0A0, 0x1F0AE), - Interval(0x1F0B1, 0x1F0BF), - Interval(0x1F0C1, 0x1F0CE), - Interval(0x1F0D1, 0x1F0F5), - Interval(0x1F10B, 0x1F10F), - Interval(0x1F12E, 0x1F12F), - Interval(0x1F16A, 0x1F16F), - Interval(0x1F1AD, 0x1F1AD), - Interval(0x1F1E6, 0x1F1FF), - Interval(0x1F321, 0x1F32C), - Interval(0x1F336, 0x1F336), - Interval(0x1F37D, 0x1F37D), - Interval(0x1F394, 0x1F39F), - Interval(0x1F3CB, 0x1F3CE), - Interval(0x1F3D4, 0x1F3DF), - Interval(0x1F3F1, 0x1F3F3), - Interval(0x1F3F5, 0x1F3F7), - Interval(0x1F43F, 0x1F43F), - Interval(0x1F441, 0x1F441), - Interval(0x1F4FD, 0x1F4FE), - Interval(0x1F53E, 0x1F54A), - Interval(0x1F54F, 0x1F54F), - Interval(0x1F568, 0x1F579), - Interval(0x1F57B, 0x1F594), - Interval(0x1F597, 0x1F5A3), - Interval(0x1F5A5, 0x1F5FA), - Interval(0x1F650, 0x1F67F), - Interval(0x1F6C6, 0x1F6CB), - Interval(0x1F6CD, 0x1F6CF), - Interval(0x1F6D3, 0x1F6D4), - Interval(0x1F6E0, 0x1F6EA), - Interval(0x1F6F0, 0x1F6F3), - Interval(0x1F700, 0x1F773), - Interval(0x1F780, 0x1F7D8), - Interval(0x1F800, 0x1F80B), - Interval(0x1F810, 0x1F847), - Interval(0x1F850, 0x1F859), - Interval(0x1F860, 0x1F887), - Interval(0x1F890, 0x1F8AD), - Interval(0x1F8B0, 0x1F8B1), - Interval(0x1F900, 0x1F90B), - Interval(0x1F93B, 0x1F93B), - Interval(0x1F946, 0x1F946), - Interval(0x1FA00, 0x1FA53), - Interval(0x1FA60, 0x1FA6D), - Interval(0x1FB00, 0x1FB92), - Interval(0x1FB94, 0x1FBCA), - Interval(0x1FBF0, 0x1FBF9), - Interval(0xE0001, 0xE0001), - Interval(0xE0020, 0xE007F), -) - -alias emoji = List[Interval]( - Interval(0x203C, 0x203C), - Interval(0x2049, 0x2049), - Interval(0x2122, 0x2122), - Interval(0x2139, 0x2139), - Interval(0x2194, 0x2199), - Interval(0x21A9, 0x21AA), - Interval(0x231A, 0x231B), - Interval(0x2328, 0x2328), - Interval(0x2388, 0x2388), - Interval(0x23CF, 0x23CF), - Interval(0x23E9, 0x23F3), - Interval(0x23F8, 0x23FA), - Interval(0x24C2, 0x24C2), - Interval(0x25AA, 0x25AB), - Interval(0x25B6, 0x25B6), - Interval(0x25C0, 0x25C0), - Interval(0x25FB, 0x25FE), - Interval(0x2600, 0x2605), - Interval(0x2607, 0x2612), - Interval(0x2614, 0x2685), - Interval(0x2690, 0x2705), - Interval(0x2708, 0x2712), - Interval(0x2714, 0x2714), - Interval(0x2716, 0x2716), - Interval(0x271D, 0x271D), - Interval(0x2721, 0x2721), - Interval(0x2728, 0x2728), - Interval(0x2733, 0x2734), - Interval(0x2744, 0x2744), - Interval(0x2747, 0x2747), - Interval(0x274C, 0x274C), - Interval(0x274E, 0x274E), - Interval(0x2753, 0x2755), - Interval(0x2757, 0x2757), - Interval(0x2763, 0x2767), - Interval(0x2795, 0x2797), - Interval(0x27A1, 0x27A1), - Interval(0x27B0, 0x27B0), - Interval(0x27BF, 0x27BF), - Interval(0x2934, 0x2935), - Interval(0x2B05, 0x2B07), - Interval(0x2B1B, 0x2B1C), - Interval(0x2B50, 0x2B50), - Interval(0x2B55, 0x2B55), - Interval(0x3030, 0x3030), - Interval(0x303D, 0x303D), - Interval(0x3297, 0x3297), - Interval(0x3299, 0x3299), - Interval(0x1F000, 0x1F0FF), - Interval(0x1F10D, 0x1F10F), - Interval(0x1F12F, 0x1F12F), - Interval(0x1F16C, 0x1F171), - Interval(0x1F17E, 0x1F17F), - Interval(0x1F18E, 0x1F18E), - Interval(0x1F191, 0x1F19A), - Interval(0x1F1AD, 0x1F1E5), - Interval(0x1F201, 0x1F20F), - Interval(0x1F21A, 0x1F21A), - Interval(0x1F22F, 0x1F22F), - Interval(0x1F232, 0x1F23A), - Interval(0x1F23C, 0x1F23F), - Interval(0x1F249, 0x1F3FA), - Interval(0x1F400, 0x1F53D), - Interval(0x1F546, 0x1F64F), - Interval(0x1F680, 0x1F6FF), - Interval(0x1F774, 0x1F77F), - Interval(0x1F7D5, 0x1F7FF), - Interval(0x1F80C, 0x1F80F), - Interval(0x1F848, 0x1F84F), - Interval(0x1F85A, 0x1F85F), - Interval(0x1F888, 0x1F88F), - Interval(0x1F8AE, 0x1F8FF), - Interval(0x1F90C, 0x1F93A), - Interval(0x1F93C, 0x1F945), - Interval(0x1F947, 0x1FAFF), - Interval(0x1FC00, 0x1FFFD), -) - -alias private = List[Interval]( - Interval(0x00E000, 0x00F8FF), - Interval(0x0F0000, 0x0FFFFD), - Interval(0x100000, 0x10FFFD), -) - -alias nonprint = List[Interval]( - Interval(0x0000, 0x001F), - Interval(0x007F, 0x009F), - Interval(0x00AD, 0x00AD), - Interval(0x070F, 0x070F), - Interval(0x180B, 0x180E), - Interval(0x200B, 0x200F), - Interval(0x2028, 0x202E), - Interval(0x206A, 0x206F), - Interval(0xD800, 0xDFFF), - Interval(0xFEFF, 0xFEFF), - Interval(0xFFF9, 0xFFFB), - Interval(0xFFFE, 0xFFFF), -) diff --git a/external/gojo/unicode/utf8/width.mojo b/external/gojo/unicode/utf8/width.mojo deleted file mode 100644 index 8a09ed7..0000000 --- a/external/gojo/unicode/utf8/width.mojo +++ /dev/null @@ -1,106 +0,0 @@ -from .table import Interval, narrow, combining, doublewidth, ambiguous, emoji, nonprint -from .string import UnicodeString - - -@value -struct Condition: - """Condition have flag EastAsianWidth whether the current locale is CJK or not.""" - - var east_asian_width: Bool - var strict_emoji_neutral: Bool - - fn rune_width(self, r: UInt32) -> Int: - """Returns the number of cells in r. - See http://www.unicode.org/reports/tr11/.""" - if r < 0 or r > 0x10FFFF: - return 0 - - if not self.east_asian_width: - if r < 0x20: - return 0 - # nonprint - elif (r >= 0x7F and r <= 0x9F) or r == 0xAD: - return 0 - elif r < 0x300: - return 1 - elif in_table(r, narrow): - return 1 - elif in_tables(r, nonprint, combining): - return 0 - elif in_table(r, doublewidth): - return 2 - else: - return 1 - else: - if in_tables(r, nonprint, combining): - return 0 - elif in_table(r, narrow): - return 1 - elif in_tables(r, ambiguous, doublewidth): - return 2 - elif in_table(r, ambiguous) or in_table(r, emoji): - return 2 - elif not self.strict_emoji_neutral and in_tables(r, ambiguous, emoji, narrow): - return 2 - else: - return 1 - - fn string_width(self, s: String) -> Int: - """Return width as you can see.""" - var width = 0 - for r in UnicodeString(s): - width += self.rune_width(ord(String(r))) - return width - - -fn in_tables(r: UInt32, *ts: List[Interval]) -> Bool: - for t in ts: - if in_table(r, t[]): - return True - return False - - -fn in_table(r: UInt32, t: List[Interval]) -> Bool: - if r < t[0].first: - return False - - var bot = 0 - var top = len(t) - 1 - while top >= bot: - var mid = (bot + top) >> 1 - - if t[mid].last < r: - bot = mid + 1 - elif t[mid].first > r: - top = mid - 1 - else: - return True - - return False - - -alias DEFAULT_CONDITION = Condition(east_asian_width=False, strict_emoji_neutral=True) - - -fn string_width(s: String) -> Int: - """Return width as you can see. - - Args: - s: The string to calculate the width of. - - Returns: - The printable width of the string. - """ - return DEFAULT_CONDITION.string_width(s) - - -fn rune_width(rune: UInt32) -> Int: - """Return width as you can see. - - Args: - rune: The rune to calculate the width of. - - Returns: - The printable width of the rune. - """ - return DEFAULT_CONDITION.rune_width(rune) diff --git a/external/hue/__init__.mojo b/external/hue/__init__.mojo deleted file mode 100644 index e33cdab..0000000 --- a/external/hue/__init__.mojo +++ /dev/null @@ -1 +0,0 @@ -from .color import Color diff --git a/external/hue/color.mojo b/external/hue/color.mojo deleted file mode 100644 index b3cb642..0000000 --- a/external/hue/color.mojo +++ /dev/null @@ -1,1132 +0,0 @@ -import math -from .math import cube, clamp01, sq, pi, max_float64 -from .hsluv import hSLuvD65, LuvLCh_to_HPLuv, LuvLch_to_HSLuv - - -# This is the tolerance used when comparing colors using AlmostEqualColor. -alias Delta = 1.0 / 255.0 - -# This is the default reference white point. -alias D65 = List[Float64](0.95047, 1.00000, 1.08883) - -# And another one. -alias D50 = List[Float64](0.96422, 1.00000, 0.82521) - - -@value -struct Color(Stringable): - var R: Float64 - var G: Float64 - var B: Float64 - - fn __str__(self) -> String: - return "Color(" + str(self.R) + ", " + str(self.G) + ", " + str(self.B) + ")" - - fn linear_rgb(self) -> (Float64, Float64, Float64): - """Converts the color into the linear Color space (see http://www.sjbrown.co.uk/2004/05/14/gamma-correct-rendering/). - """ - var r = linearize(self.R) - var g = linearize(self.G) - var b = linearize(self.B) - return r, g, b - - fn xyz(self) -> (Float64, Float64, Float64): - var r: Float64 - var g: Float64 - var b: Float64 - r, g, b = self.linear_rgb() - - var x: Float64 - var y: Float64 - var z: Float64 - x, y, z = linear_rgb_to_xyz(r, g, b) - return x, y, z - - fn Luv_white_ref(self, wref: List[Float64]) -> (Float64, Float64, Float64): - """Converts the given color to CIE L*u*v* space, taking into account a given reference white. (i.e. the monitor's white) - L* is in [0..1] and both u* and v* are in about [-1..1].""" - var x: Float64 - var y: Float64 - var z: Float64 - x, y, z = self.xyz() - - var l: Float64 - var u: Float64 - var v: Float64 - l, u, v = xyz_to_Luv_white_ref(x, y, z, wref) - return l, u, v - - fn LuvLCh_white_ref(self, wref: List[Float64]) -> (Float64, Float64, Float64): - var l: Float64 - var u: Float64 - var v: Float64 - l, u, v = self.Luv_white_ref(wref) - - return Luv_To_LuvLCh(l, u, v) - - fn HSLuv(self) -> (Float64, Float64, Float64): - """Order: sColor -> Linear Color -> CIEXYZ -> CIELUV -> LuvLCh -> HSLuv. - HSLuv returns the Hue, Saturation and Luminance of the color in the HSLuv - color space. Hue in [0..360], a Saturation [0..1], and a Luminance - (lightness) in [0..1]. - """ - var wref: List[Float64] = hSLuvD65 - var l: Float64 - var c: Float64 - var h: Float64 - l, c, h = self.LuvLCh_white_ref(wref) - - return LuvLch_to_HSLuv(l, c, h) - - fn distance_HSLuv(self, c2: Self) -> Float64: - var h1: Float64 - var s1: Float64 - var l1: Float64 - var h2: Float64 - var s2: Float64 - var l2: Float64 - - h1, s1, l1 = self.HSLuv() - h2, s2, l2 = c2.HSLuv() - - return math.sqrt(sq((h1 - h2) / 100.0) + sq(s1 - s2) + sq(l1 - l2)) - - fn is_valid(self) -> Bool: - """Checks whether the color exists in RGB space, i.e. all values are in [0..1].""" - return 0.0 <= self.R and self.R <= 1.0 and 0.0 <= self.G and self.G <= 1.0 and 0.0 <= self.B and self.B <= 1.0 - - fn clamped(self) -> Self: - """Clamps the color to the [0..1] range. If the color is valid already, this is a no-op.""" - return Color(clamp01(self.R), clamp01(self.G), clamp01(self.B)) - - fn distance_rgb(self, c2: Self) -> Float64: - """Computes the distance between two colors in RGB space. - This is not a good measure! Rather do it in Lab space.""" - return math.sqrt(sq(self.R - c2.R) + sq(self.G - c2.G) + sq(self.B - c2.B)) - - fn distance_linear_rgb(self, c2: Self) -> Float64: - """Computes the distance between two colors in linear RGB space. - This is not useful for measuring how humans perceive color, but - might be useful for other things, like dithering.""" - var r1: Float64 - var g1: Float64 - var b1: Float64 - r1, g1, b1 = self.linear_rgb() - var r2: Float64 - var g2: Float64 - var b2: Float64 - r2, g2, b2 = c2.linear_rgb() - return math.sqrt(sq(r1 - r2) + sq(g1 - g2) + sq(b1 - b2)) - - fn distance_riemersma(self, c2: Self) -> Float64: - """Color distance algorithm developed by Thiadmer Riemersma. - It uses RGB coordinates, but he claims it has similar results to CIELUV. - This makes it both fast and accurate. - - Sources: - - https:#www.compuphase.com/cmetric.htm - https:#github.com/lucasb-eyer/go-colorful/issues/52.""" - var rAvg = (self.R + c2.R) / 2.0 - # Deltas - var dR = self.R - c2.R - var dG = self.G - c2.G - var dB = self.B - c2.B - return math.sqrt(((2 + rAvg) * dR * dR) + (4 * dG * dG) + (2 + (1 - rAvg)) * dB * dB) - - fn almost_equal_rgb(self, c2: Self) -> Bool: - """Check for equality between colors within the tolerance Delta (1/255).""" - return abs(self.R - c2.R) + abs(self.G - c2.G) + abs(self.B - c2.B) < 3.0 * Delta - - fn hsv(self) -> (Float64, Float64, Float64): - """Hsv returns the Hue [0..360], Saturation and Value [0..1] of the color.""" - var min = min(min(self.R, self.G), self.B) - var v = max(max(self.R, self.G), self.B) - var C = v - min - - var s = 0.0 - if v != 0.0: - s = C / v - - var h = 0.0 # We use 0 instead of undefined as in wp. - if min != v: - if v == self.R: - h = (self.G - self.B) / C % 6.0 - if v == self.G: - h = (self.B - self.R) / C + 2.0 - if v == self.B: - h = (self.R - self.G) / C + 4.0 - h *= 60.0 - if h < 0.0: - h += 360.0 - return h, s, v - - fn hsl(self) -> (Float64, Float64, Float64): - """Hsl returns the Hue [0..360], Saturation [0..1], and Luminance (lightness) [0..1] of the color.""" - var min = min(min(self.R, self.G), self.B) - var max = max(max(self.R, self.G), self.B) - - var l = (max + min) / 2.0 - - if min == max: - return 0.0, 0.0, l - - var s = 0.0 - if l < 0.5: - s = (max - min) / (max + min) - else: - s = (max - min) / (2.0 - max - min) - - var h = 0.0 - if max == self.R: - h = (self.G - self.B) / (max - min) - elif max == self.G: - h = 2.0 + (self.B - self.R) / (max - min) - else: - h = 4.0 + (self.R - self.G) / (max - min) - - h *= 60.0 - - if h < 0.0: - h += 360.0 - - return h, s, l - - # fn hex(self) -> String: - # """Hex returns the hex "html" representation of the color, as in #ff0080.""" - # # Add 0.5 for rounding - # return "#" + {UInt8(self.R * 255.0 + 0.5):02x} + {UInt8(self.G * 255.0 + 0.5):02x} + {UInt8(self.B * 255.0 + 0.5):02x} - # # return fmt.Sprintf("#%02x%02x%02x", uint8(col.R*255.0+0.5), uint8(col.G*255.0+0.5), uint8(col.B*255.0+0.5)) - - fn fast_linear_rgb(self) -> (Float64, Float64, Float64): - """Is much faster than and almost as accurate as LinearRgb. - BUT it is important to NOTE that they only produce good results for valid colors r,g,b in [0,1]. - """ - return ( - delinearize_fast(self.R), - delinearize_fast(self.G), - delinearize_fast(self.B), - ) - - fn blend_linear_rgb(self, c2: Self, t: Float64) -> Self: - """Blends two colors in the Linear RGB color-space. - Unlike BlendRgb, this will not produce dark color around the center. - t == 0 results in c1, t == 1 results in c2.""" - var r1: Float64 - var g1: Float64 - var b1: Float64 - r1, g1, b1 = self.linear_rgb() - - var r2: Float64 - var g2: Float64 - var b2: Float64 - r2, g2, b2 = c2.linear_rgb() - return fast_linear_rgb( - r1 + t * (r2 - r1), - g1 + t * (g2 - g1), - b1 + t * (b2 - b1), - ) - - fn xyy(self) -> (Float64, Float64, Float64): - """Converts the given color to CIE xyY space using D65 as reference white. - (Note that the reference white is only used for black input.) - x, y and Y are in [0..1].""" - var X: Float64 - var Y: Float64 - var Z: Float64 - X, Y, Z = self.xyz() - return xyz_to_xyY(X, Y, Z) - - fn xyy_white_ref(self, wref: List[Float64]) -> (Float64, Float64, Float64): - """Converts the given color to CIE xyY space, taking into account - a given reference white. (i.e. the monitor's white) - (Note that the reference white is only used for black input.) - x, y and Y are in [0..1].""" - var X: Float64 - var Y2: Float64 - var Z: Float64 - X, Y2, Z = self.xyz() - return xyz_to_xyY_white_ref(X, Y2, Z, wref) - - fn lab(self) -> (Float64, Float64, Float64): - """Converts the given color to CIE L*a*b* space using D65 as reference white.""" - var x: Float64 - var y: Float64 - var z: Float64 - x, y, z = self.xyz() - return xyz_to_lab(x, y, z) - - fn lab_white_ref(self, wref: List[Float64]) -> (Float64, Float64, Float64): - """Converts the given color to CIE L*a*b* space, taking into account - a given reference white. (i.e. the monitor's white).""" - var x: Float64 - var y: Float64 - var z: Float64 - x, y, z = self.xyz() - return xyz_to_lab_white_ref(x, y, z, wref) - - fn distance_lab(self, other: Self) -> Float64: - """DistanceLab is a good measure of visual similarity between two colors! - A result of 0 would mean identical colors, while a result of 1 or higher - means the colors differ a lot.""" - var l1: Float64 - var a1: Float64 - var b1: Float64 - l1, a1, b1 = self.lab() - - var l2: Float64 - var a2: Float64 - var b2: Float64 - l2, a2, b2 = other.lab() - - return math.sqrt(sq(l1 - l2) + sq(a1 - a2) + sq(b1 - b2)) - - fn distance_cie76(self, other: Self) -> Float64: - """DistanceCIE76 is the same as DistanceLab.""" - return self.distance_lab(other) - - fn distance_cie94(self, other: Self) -> Float64: - """Uses the CIE94 formula to calculate color distance. More accurate than - DistanceLab, but also more work.""" - var l1: Float64 - var a1: Float64 - var b1: Float64 - l1, a1, b1 = self.lab() - - var l2: Float64 - var a2: Float64 - var b2: Float64 - l2, a2, b2 = other.lab() - - # NOTE: Since all those formulas expect L,a,b values 100x larger than we - # have them in this library, we either need to adjust all constants - # in the formula, or convert the ranges of L,a,b before, and then - # scale the distances down again. The latter is less error-prone. - l1 *= 100.0 - a1 *= 100.0 - b1 *= 100.0 - l2 *= 100.0 - a2 *= 100.0 - b2 *= 100.0 - - var kl = 1.0 # 2.0 for textiles - var kc = 1.0 - var kh = 1.0 - var k1 = 0.045 # 0.048 for textiles - var k2 = 0.015 # 0.014 for textiles. - - var deltaL = l1 - l2 - var c1 = math.sqrt(sq(a1) + sq(b1)) - var c2 = math.sqrt(sq(a2) + sq(b2)) - var deltaCab = c1 - c2 - - # Not taking Sqrt here for stability, and it's unnecessary. - var deltaHab2 = sq(a1 - a2) + sq(b1 - b2) - sq(deltaCab) - var sl = 1.0 - var sc = 1.0 + k1 * c1 - var sh = 1.0 + k2 * c1 - - var vL2 = sq(deltaL / (kl * sl)) - var vC2 = sq(deltaCab / (kc * sc)) - var vH2 = deltaHab2 / sq(kh * sh) - - return math.sqrt(vL2 + vC2 + vH2) * 0.01 # See above. - - fn distance_ciede2000(self, other: Self) -> Float64: - """DistanceCIEDE2000 uses the Delta E 2000 formula to calculate color - distance. It is more expensive but more accurate than both DistanceLab - and DistanceCIE94.""" - return self.distance_ciede2000klch(other, 1.0, 1.0, 1.0) - - fn distance_ciede2000klch(self, other: Self, kl: Float64, kc: Float64, kh: Float64) -> Float64: - """DistanceCIEDE2000klch uses the Delta E 2000 formula with custom values - for the weighting factors kL, kC, and kH.""" - var l1: Float64 - var a1: Float64 - var b1: Float64 - l1, a1, b1 = self.lab() - - var l2: Float64 - var a2: Float64 - var b2: Float64 - l2, a2, b2 = other.lab() - - # As with CIE94, we scale up the ranges of L,a,b beforehand and scale - # them down again afterwards. - l1 *= 100.0 - a1 *= 100.0 - b1 *= 100.0 - l2 *= 100.0 - a2 *= 100.0 - b2 *= 100.0 - - var cab1 = math.sqrt(sq(a1) + sq(b1)) - var cab2 = math.sqrt(sq(a2) + sq(b2)) - var cabmean = (cab1 + cab2) / 2 - var p: Float64 = 25.0 - - var g = 0.5 * (1 - math.sqrt((cabmean**7) / ((cabmean**7) + (p**7)))) - var ap1 = (1 + g) * a1 - var ap2 = (1 + g) * a2 - var cp1 = math.sqrt(sq(ap1) + sq(b1)) - var cp2 = math.sqrt(sq(ap2) + sq(b2)) - - var hp1 = 0.0 - if b1 != ap1 or ap1 != 0: - hp1 = math.atan2(b1, ap1) - if hp1 < 0: - hp1 += pi * 2 - hp1 *= 180 / pi - var hp2 = 0.0 - if b2 != ap2 or ap2 != 0: - hp2 = math.atan2(b2, ap2) - if hp2 < 0: - hp2 += pi * 2 - hp2 *= 180 / pi - - var deltaLp = l2 - l1 - var deltaCp = cp2 - cp1 - var dhp = 0.0 - var cpProduct = cp1 * cp2 - if cpProduct != 0: - dhp = hp2 - hp1 - if dhp > 180: - dhp -= 360 - elif dhp < -180: - dhp += 360 - var deltaHp = 2 * math.sqrt(cpProduct) * math.sin(dhp / 2 * pi / 180) - - var lpmean = (l1 + l2) / 2 - var cpmean = (cp1 + cp2) / 2 - var hpmean = hp1 + hp2 - if cpProduct != 0: - hpmean /= 2 - if abs(hp1 - hp2) > 180: - if hp1 + hp2 < 360: - hpmean += 180 - else: - hpmean -= 180 - - var t = 1 - 0.17 * math.cos((hpmean - 30) * pi / 180) + 0.24 * math.cos( - 2 * hpmean * pi / 180 - ) + 0.32 * math.cos((3 * hpmean + 6) * pi / 180) - 0.2 * math.cos((4 * hpmean - 63) * pi / 180) - var deltaTheta = 30 * math.exp(-sq((hpmean - 275) / 25)) - var rc = 2 * math.sqrt((cpmean**7) / ((cpmean**7) + (p**7))) - var sl = 1 + (0.015 * sq(lpmean - 50)) / math.sqrt(20 + sq(lpmean - 50)) - var sc = 1 + 0.045 * cpmean - var sh = 1 + 0.015 * cpmean * t - var rt = -math.sin(2 * deltaTheta * pi / 180) * rc - - return ( - math.sqrt( - sq(deltaLp / (kl * sl)) - + sq(deltaCp / (kc * sc)) - + sq(deltaHp / (kh * sh)) - + rt * (deltaCp / (kc * sc)) * (deltaHp / (kh * sh)) - ) - * 0.01 - ) - - fn blend_lab(self, c2: Self, t: Float64) -> Self: - """BlendLab blends two colors in the L*a*b* color-space, which should result in a smoother blend. - t == 0 results in c1, t == 1 results in c2.""" - var l1: Float64 - var a1: Float64 - var b1: Float64 - l1, a1, b1 = self.lab() - - var l2: Float64 - var a2: Float64 - var b2: Float64 - l2, a2, b2 = c2.lab() - - return lab(l1 + t * (l2 - l1), a1 + t * (a2 - a1), b1 + t * (b2 - b1)) - - fn luv(self) -> (Float64, Float64, Float64): - """Converts the given color to CIE L*u*v* space using D65 as reference white. - L* is in [0..1] and both u* and v* are in about [-1..1].""" - var x: Float64 - var y: Float64 - var z: Float64 - x, y, z = self.xyz() - return xyz_to_Luv(x, y, z) - - fn distance_luv(self, c2: Self) -> Float64: - """DistanceLuv is a good measure of visual similarity between two colors! - A result of 0 would mean identical colors, while a result of 1 or higher - means the colors differ a lot.""" - var l1: Float64 - var u1: Float64 - var v1: Float64 - l1, u1, v1 = self.luv() - - var l2: Float64 - var u2: Float64 - var v2: Float64 - l2, u2, v2 = c2.luv() - - return math.sqrt(sq(l1 - l2) + sq(u1 - u2) + sq(v1 - v2)) - - fn blend_luv(self, c2: Self, t: Float64) -> Self: - """BlendLuv blends two colors in the CIE-L*u*v* color-space, which should result in a smoother blend. - t == 0 results in c1, t == 1 results in c2.""" - var l1: Float64 - var u1: Float64 - var v1: Float64 - l1, u1, v1 = self.luv() - - var l2: Float64 - var u2: Float64 - var v2: Float64 - l2, u2, v2 = c2.luv() - - return Luv(l1 + t * (l2 - l1), u1 + t * (u2 - u1), v1 + t * (v2 - v1)) - - fn hcl(self) -> (Float64, Float64, Float64): - """Converts the given color to HCL space using D65 as reference white. - H values are in [0..360], C and L values are in [0..1] although C can overshoot 1.0. - """ - return self.hcl_white_ref(D65) - - fn hcl_white_ref(self, wref: List[Float64]) -> (Float64, Float64, Float64): - """Converts the given color to HCL space, taking into account - a given reference white. (i.e. the monitor's white) - H values are in [0..360], C and L values are in [0..1].""" - var L: Float64 - var a: Float64 - var b: Float64 - L, a, b = self.lab_white_ref(wref) - return lab_to_hcl(L, a, b) - - fn blend_hcl(self, other: Self, t: Float64) -> Self: - """BlendHcl blends two colors in the CIE-L*C*h° color-space, which should result in a smoother blend. - t == 0 results in c1, t == 1 results in c2.""" - var h1: Float64 - var c1: Float64 - var l1: Float64 - h1, c1, l1 = self.hcl() - - var h2: Float64 - var c2: Float64 - var l2: Float64 - h2, c2, l2 = other.hcl() - - # https:#github.com/lucasb-eyer/go-colorful/pull/60 - if c1 <= 0.00015 and c2 >= 0.00015: - h1 = h2 - elif c2 <= 0.00015 and c1 >= 0.00015: - h2 = h1 - - # We know that h are both in [0..360] - return hcl(interp_angle(h1, h2, t), c1 + t * (c2 - c1), l1 + t * (l2 - l1)).clamped() - - fn LuvLCh(self) -> (Float64, Float64, Float64): - """Converts the given color to LuvLCh space using D65 as reference white. - h values are in [0..360], C and L values are in [0..1] although C can overshoot 1.0. - """ - return self.Luv_LCh_white_ref(D65) - - fn Luv_LCh_white_ref(self, wref: List[Float64]) -> (Float64, Float64, Float64): - """Converts the given color to LuvLCh space, taking into account - a given reference white. (i.e. the monitor's white) - h values are in [0..360], c and l values are in [0..1].""" - var l: Float64 - var u: Float64 - var v: Float64 - l, u, v = self.Luv_white_ref(wref) - return Luv_To_LuvLCh(l, u, v) - - fn blend_Luv_LCh(self, other: Self, t: Float64) -> Self: - """BlendLuvLCh blends two colors in the cylindrical CIELUV color space. - t == 0 results in c1, t == 1 results in c2.""" - var l1: Float64 - var c1: Float64 - var h1: Float64 - l1, c1, h1 = self.LuvLCh() - - var l2: Float64 - var c2: Float64 - var h2: Float64 - l2, c2, h2 = other.LuvLCh() - - # We know that h are both in [0..360] - return LuvLCh(l1 + t * (l2 - l1), c1 + t * (c2 - c1), interp_angle(h1, h2, t)) - - fn HPLuv(self) -> (Float64, Float64, Float64): - """HPLuv returns the Hue, Saturation and Luminance of the color in the HSLuv - color space. Hue in [0..360], a Saturation [0..1], and a Luminance - (lightness) in [0..1]. - - Note that HPLuv can only represent pastel colors, and so the Saturation - value could be much larger than 1 for colors it can't represent.""" - var l: Float64 - var c: Float64 - var h: Float64 - l, c, h = self.LuvLCh_white_ref(hSLuvD65) - return LuvLCh_to_HPLuv(l, c, h) - - -fn interp_angle(a0: Float64, a1: Float64, t: Float64) -> Float64: - """Utility used by Hxx color-spaces for interpolating between two angles in [0,360].""" - # Based on the answer here: http://stackoverflow.com/a/14498790/2366315 - # With potential proof that it works here: http://math.stackexchange.com/a/2144499 - var delta = ((((a1 - a0) % 360.0) + 540.0)) % 360.0 - 180.0 - return (a0 + t * delta + 360.0) % 360.0 - - -### HSV ### -########### -# From http://en.wikipedia.org/wiki/HSL_and_HSV -# Note that h is in [0..360] and s,v in [0..1] - - -fn hsv(h: Float64, s: Float64, v: Float64) -> Color: - """Hsv creates a new Color given a Hue in [0..360], a Saturation and a Value in [0..1].""" - var hp = h / 60.0 - var C = v * s - var X = C * (1.0 - abs((hp % 2.0) - 1.0)) - var m = v - C - var r = 0.0 - var g = 0.0 - var b = 0.0 - - if 0.0 <= hp and hp < 1.0: - r = C - g = X - elif 1.0 <= hp and hp < 2.0: - r = X - g = C - elif 2.0 <= hp and hp < 3.0: - g = C - b = X - elif 3.0 <= hp and hp < 4.0: - g = X - b = C - elif 4.0 <= hp and hp < 5.0: - r = X - b = C - elif 5.0 <= hp and hp < 6.0: - r = C - b = X - - return Color(m + r, m + g, m + b) - - -## HSL ## -######### - - -fn hsl(h: Float64, s: Float64, l: Float64) -> Color: - """Hsl creates a new Color given a Hue in [0..360], a Saturation [0..1], and a Luminance (lightness) in [0..1].""" - if s == 0: - return Color(l, l, l) - - var r: Float64 - var g: Float64 - var b: Float64 - var t1: Float64 - var t2: Float64 - var tr: Float64 - var tg: Float64 - var tb: Float64 - - if l < 0.5: - t1 = l * (1.0 + s) - else: - t1 = l + s - l * s - - t2 = 2 * l - t1 - var h_copy = h - h_copy /= 360 - tr = h_copy + 1.0 / 3.0 - tg = h_copy - tb = h_copy - 1.0 / 3.0 - - if tr < 0: - tr += 1 - if tr > 1: - tr -= 1 - if tg < 0: - tg += 1 - if tg > 1: - tg -= 1 - if tb < 0: - tb += 1 - if tb > 1: - tb -= 1 - - # Red - if 6 * tr < 1: - r = t2 + (t1 - t2) * 6 * tr - elif 2 * tr < 1: - r = t1 - elif 3 * tr < 2: - r = t2 + (t1 - t2) * (2.0 / 3.0 - tr) * 6 - else: - r = t2 - - # Green - if 6 * tg < 1: - g = t2 + (t1 - t2) * 6 * tg - elif 2 * tg < 1: - g = t1 - elif 3 * tg < 2: - g = t2 + (t1 - t2) * (2.0 / 3.0 - tg) * 6 - else: - g = t2 - - # Blue - if 6 * tb < 1: - b = t2 + (t1 - t2) * 6 * tb - elif 2 * tb < 1: - b = t1 - elif 3 * tb < 2: - b = t2 + (t1 - t2) * (2.0 / 3.0 - tb) * 6 - else: - b = t2 - - return Color(r, g, b) - - -## Hex ## -######### -# # Hex parses a "html" hex color-string, either in the 3 "#f0c" or 6 "#ff1034" digits form. -# func Hex(scol string) (Color, error) { -# format := "#%02x%02x%02x" -# factor := 1.0 / 255.0 -# if len(scol) == 4 { -# format = "#%1x%1x%1x" -# factor = 1.0 / 15.0 -# } - -# var r, g, b UInt8 -# n, err := fmt.Sscanf(scol, format, &r, &g, &b) -# if err != nil { -# return Color{}, err -# } -# if n != 3 { -# return Color{}, fmt.Errorf("color: %v is not a hex-color", scol) -# } - -# return Color{float64(r) * factor, float64(g) * factor, float64(b) * factor}, nil -# } - - -## Linear ## -####### -# A much faster and still quite precise linearization using a 6th-order Taylor approximation. -# See the accompanying Jupyter notebook for derivation of the constants. -fn linearize_fast(v: Float64) -> Float64: - var v1 = v - 0.5 - var v2 = v1 * v1 - var v3 = v2 * v1 - var v4 = v2 * v2 - return ( - -0.248750514614486 - + 0.925583310193438 * v - + 1.16740237321695 * v2 - + 0.280457026598666 * v3 - - 0.0757991963780179 * v4 - ) - - -fn delinearize_fast(v: Float64) -> Float64: - if v > 0.2: - var v1 = v - 0.6 - var v2 = v1 * v1 - var v3 = v2 * v1 - var v4 = v2 * v2 - var v5 = v3 * v2 - return ( - 0.442430344268235 - + 0.592178981271708 * v - - 0.287864782562636 * v2 - + 0.253214392068985 * v3 - - 0.272557158129811 * v4 - + 0.325554383321718 * v5 - ) - elif v > 0.03: - var v1 = v - 0.115 - var v2 = v1 * v1 - var v3 = v2 * v1 - var v4 = v2 * v2 - var v5 = v3 * v2 - return ( - 0.194915592891669 - + 1.55227076330229 * v - - 3.93691860257828 * v2 - + 18.0679839248761 * v3 - - 101.468750302746 * v4 - + 632.341487393927 * v5 - ) - else: - var v1 = v - 0.015 - var v2 = v1 * v1 - var v3 = v2 * v1 - var v4 = v2 * v2 - var v5 = v3 * v2 - return ( - 0.0519565234928877 - + 5.09316778537561 * v - - 99.0338180489702 * v2 - + 3484.52322764895 * v3 - - 150028.083412663 * v4 - + 7168008.42971613 * v5 - ) - - -# FastLinearRgb is much faster than and almost as accurate as LinearRgb. -# BUT it is important to NOTE that they only produce good results for valid inputs r,g,b in [0,1]. -fn fast_linear_rgb(r: Float64, g: Float64, b: Float64) -> Color: - return Color(delinearize_fast(r), delinearize_fast(g), delinearize_fast(b)) - - -fn xyz_to_xyY(X: Float64, Y: Float64, Z: Float64) -> (Float64, Float64, Float64): - return xyz_to_xyY_white_ref(X, Y, Z, D65) - - -fn xyz_to_xyY_white_ref(X: Float64, Y: Float64, Z: Float64, wref: List[Float64]) -> (Float64, Float64, Float64): - var Yout = Y - var N = X + Y + Z - var x = X - var y = Y - if abs(N) < 1e-14: - x = wref[0] / (wref[0] + wref[1] + wref[2]) - y = wref[1] / (wref[0] + wref[1] + wref[2]) - else: - x = x / N - y = y / N - - return x, y, Yout - - -fn xyy_to_xyz(x: Float64, y: Float64, Y: Float64) -> (Float64, Float64, Float64): - var Yout = y - var X = x - var Z = 0.0 - - if -1e-14 < y and y < 1e-14: - X = 0.0 - Z = 0.0 - else: - X = Y / y * x - Z = Y / y * (1.0 - x - y) - - return x, y, Yout - - -fn xyy(x: Float64, y: Float64, Y: Float64) -> Color: - var X: Float64 - var new_Y: Float64 - var Z: Float64 - X, new_Y, Z = xyy_to_xyz(x, y, Y) - return xyz(X, new_Y, Z) - - -# / L*a*b* #/ -####### -# http://en.wikipedia.org/wiki/Lab_color_space#CIELAB-CIEXYZ_conversions -# For L*a*b*, we need to L*a*b*<->XYZ->RGB and the first one is device dependent. - - -fn lab_f(t: Float64) -> Float64: - if t > 6.0 / 29.0 * 6.0 / 29.0 * 6.0 / 29.0: - return math.cbrt(t) - return t / 3.0 * 29.0 / 6.0 * 29.0 / 6.0 + 4.0 / 29.0 - - -fn xyz_to_lab(x: Float64, y: Float64, z: Float64) -> (Float64, Float64, Float64): - """Use D65 white as reference point by default. - http://www.fredmiranda.com/forum/topic/1035332 - http://en.wikipedia.org/wiki/Standard_illuminant.""" - return xyz_to_lab_white_ref(x, y, z, D65) - - -fn xyz_to_lab_white_ref(x: Float64, y: Float64, z: Float64, wref: List[Float64]) -> (Float64, Float64, Float64): - var fy = lab_f(y / wref[1]) - var l = 1.16 * fy - 0.16 - var a = 5.0 * (lab_f(x / wref[0]) - fy) - var b = 2.0 * (fy - lab_f(z / wref[2])) - return l, a, b - - -fn lab_finv(t: Float64) -> Float64: - if t > 6.0 / 29.0: - return t * t * t - return 3.0 * 6.0 / 29.0 * 6.0 / 29.0 * (t - 4.0 / 29.0) - - -fn lab_to_xyz(l: Float64, a: Float64, b: Float64) -> (Float64, Float64, Float64): - """D65 white (see above).""" - return lab_to_xyz_white_ref(l, a, b, D65) - - -fn lab_to_xyz_white_ref(l: Float64, a: Float64, b: Float64, wref: List[Float64]) -> (Float64, Float64, Float64): - var l2 = (l + 0.16) / 1.16 - var x = wref[0] * lab_finv(l2 + a / 5.0) - var y = wref[1] * lab_finv(l2) - var z = wref[2] * lab_finv(l2 - b / 2.0) - return x, y, z - - -fn lab(l: Float64, a: Float64, b: Float64) -> Color: - """Generates a color by using data given in CIE L*a*b* space using D65 as reference white. - WARNING: many combinations of `l`, `a`, and `b` values do not have corresponding - valid RGB values, check the FAQ in the README if you're unsure.""" - var x: Float64 - var y: Float64 - var z: Float64 - x, y, z = lab_to_xyz(l, a, b) - return xyz(x, y, z) - - -fn lab_white_ref(l: Float64, a: Float64, b: Float64, wref: List[Float64]) -> Color: - """Generates a color by using data given in CIE L*a*b* space, taking - into account a given reference white. (i.e. the monitor's white).""" - var x: Float64 - var y: Float64 - var z: Float64 - x, y, z = lab_to_xyz_white_ref(l, a, b, wref) - return xyz(x, y, z) - - -# / L*u*v* #/ -####### -# http://en.wikipedia.org/wiki/CIELUV#XYZ_.E2.86.92_CIELUV_and_CIELUV_.E2.86.92_XYZ_conversions -# For L*u*v*, we need to L*u*v*<->XYZ<->RGB and the first one is device dependent. - - -fn xyz_to_Luv(x: Float64, y: Float64, z: Float64) -> (Float64, Float64, Float64): - """Use D65 white as reference point by default.""" - return xyz_to_Luv_white_ref(x, y, z, D65) - - -fn luv_to_xyz(l: Float64, u: Float64, v: Float64) -> (Float64, Float64, Float64): - """Use D65 white as reference point by default.""" - return luv_to_xyz_white_ref(l, u, v, D65) - - -fn Luv(l: Float64, u: Float64, v: Float64) -> Color: - """Generates a color by using data given in CIE L*u*v* space using D65 as reference white. - L* is in [0..1] and both u* and v* are in about [-1..1] - WARNING: many combinations of `l`, `u`, and `v` values do not have corresponding - valid RGB values, check the FAQ in the README if you're unsure.""" - var x: Float64 - var y: Float64 - var z: Float64 - x, y, z = luv_to_xyz(l, u, v) - return xyz(x, y, z) - - -fn Luv_white_ref(l: Float64, u: Float64, v: Float64, wref: List[Float64]) -> Color: - """Generates a color by using data given in CIE L*u*v* space, taking - into account a given reference white. (i.e. the monitor's white) - L* is in [0..1] and both u* and v* are in about [-1..1].""" - var x: Float64 - var y: Float64 - var z: Float64 - x, y, z = luv_to_xyz_white_ref(l, u, v, wref) - return xyz(x, y, z) - - -## HCL ## -######### -# HCL is nothing else than L*a*b* in cylindrical coordinates! -# (this was wrong on English wikipedia, I fixed it, let's hope the fix stays.) -# But it is widely popular since it is a "correct HSV" -# http://www.hunterlab.com/appnotes/an09_96a.pdf - - -fn lab_to_hcl(L: Float64, a: Float64, b: Float64) -> (Float64, Float64, Float64): - var h = 0.0 - if abs(b - a) > 1e-4 and abs(a) > 1e-4: - h = (57.29577951308232087721 * math.atan2(b, a) + 360.0) % 360.0 # Rad2Deg - - var c = math.sqrt(sq(a) + sq(b)) - var l = L - return h, c, l - - -fn hcl(h: Float64, c: Float64, l: Float64) -> Color: - """Generates a color by using data given in HCL space using D65 as reference white. - H values are in [0..360], C and L values are in [0..1] - WARNING: many combinations of `h`, `c`, and `l` values do not have corresponding - valid RGB values, check the FAQ in the README if you're unsure.""" - return hcl_white_ref(h, c, l, D65) - - -fn hcl_to_Lab(h: Float64, c: Float64, l: Float64) -> (Float64, Float64, Float64): - var H = 0.01745329251994329576 * h # Deg2Rad - var a = c * math.cos(H) - var b = c * math.sin(H) - var L = l - return L, a, b - - -fn hcl_white_ref(h: Float64, c: Float64, l: Float64, wref: List[Float64]) -> Color: - """Generates a color by using data given in HCL space, taking - into account a given reference white. (i.e. the monitor's white) - H values are in [0..360], C and L values are in [0..1].""" - var L: Float64 - var a: Float64 - var b: Float64 - L, a, b = hcl_to_Lab(h, c, l) - return lab_white_ref(L, a, b, wref) - - -fn LuvLCh(l: Float64, c: Float64, h: Float64) -> Color: - """Generates a color by using data given in LuvLCh space using D65 as reference white. - h values are in [0..360], C and L values are in [0..1] - WARNING: many combinations of `l`, `c`, and `h` values do not have corresponding - valid RGB values, check the FAQ in the README if you're unsure.""" - return LuvLCh_white_ref(l, c, h, D65) - - -fn LuvLChToLuv(l: Float64, c: Float64, h: Float64) -> (Float64, Float64, Float64): - var H = 0.01745329251994329576 * h # Deg2Rad - var u = c * math.cos(H) - var v = c * math.sin(H) - var L = l - return L, u, v - - -fn LuvLCh_white_ref(l: Float64, c: Float64, h: Float64, wref: List[Float64]) -> Color: - """Generates a color by using data given in LuvLCh space, taking - into account a given reference white. (i.e. the monitor's white) - h values are in [0..360], C and L values are in [0..1].""" - var L: Float64 - var u: Float64 - var v: Float64 - L, u, v = LuvLChToLuv(l, c, h) - return Luv_white_ref(L, u, v, wref) - - -fn clamped(color: Color) -> Color: - return Color(clamp01(color.R), clamp01(color.G), clamp01(color.B)) - - -fn linearize(v: Float64) -> Float64: - if v <= 0.04045: - return v / 12.92 - - var lhs: Float64 = (v + 0.055) / 1.055 - var rhs: Float64 = 2.4 - return lhs**rhs - - -fn linear_rgb_to_xyz(r: Float64, g: Float64, b: Float64) -> (Float64, Float64, Float64): - var x: Float64 = 0.41239079926595948 * r + 0.35758433938387796 * g + 0.18048078840183429 * b - var y: Float64 = 0.21263900587151036 * r + 0.71516867876775593 * g + 0.072192315360733715 * b - var z: Float64 = 0.019330818715591851 * r + 0.11919477979462599 * g + 0.95053215224966058 * b - - return x, y, z - - -fn luv_to_xyz_white_ref(l: Float64, u: Float64, v: Float64, wref: List[Float64]) -> (Float64, Float64, Float64): - var y: Float64 - if l <= 0.08: - y = wref[1] * l * 100.0 * 3.0 / 29.0 * 3.0 / 29.0 * 3.0 / 29.0 - else: - y = wref[1] * cube((l + 0.16) / 1.16) - - var un: Float64 = 0 - var vn: Float64 = 0 - un, vn = xyz_to_uv(wref[0], wref[1], wref[2]) - - var x: Float64 = 0 - var z: Float64 = 0 - if l != 0.0: - var ubis = (u / (13.0 * l)) + un - var vbis = (v / (13.0 * l)) + vn - x = y * 9.0 * ubis / (4.0 * vbis) - z = y * (12.0 - (3.0 * ubis) - (20.0 * vbis)) / (4.0 * vbis) - else: - x = 0.0 - y = 0.0 - - return x, y, z - - -fn xyz_to_uv(x: Float64, y: Float64, z: Float64) -> (Float64, Float64): - """For this part, we do as R's graphics.hcl does, not as wikipedia does. - Or is it the same.""" - var denom = x + (15.0 * y) + (3.0 * z) - var u: Float64 - var v: Float64 - - if denom == 0.0: - u = 0.0 - v = 0.0 - - return u, v - - u = 4.0 * x / denom - v = 9.0 * y / denom - - return u, v - - -fn xyz_to_Luv_white_ref(x: Float64, y: Float64, z: Float64, wref: List[Float64]) -> (Float64, Float64, Float64): - var l: Float64 - if y / wref[1] <= 6.0 / 29.0 * 6.0 / 29.0 * 6.0 / 29.0: - l = y / wref[1] * (29.0 / 3.0 * 29.0 / 3.0 * 29.0 / 3.0) / 100.0 - else: - l = 1.16 * math.cbrt(y / wref[1]) - 0.16 - - var ubis: Float64 - var vbis: Float64 - ubis, vbis = xyz_to_uv(x, y, z) - - var un: Float64 - var vn: Float64 - un, vn = xyz_to_uv(wref[0], wref[1], wref[2]) - - var u: Float64 - var v: Float64 - u = 13.0 * l * (ubis - un) - v = 13.0 * l * (vbis - vn) - - return l, u, v - - -fn Luv_To_LuvLCh(L: Float64, u: Float64, v: Float64) -> (Float64, Float64, Float64): - # Oops, floating point workaround necessary if u ~= v and both are very small (i.e. almost zero). - var h: Float64 - if abs(v - u) > 1e-4 and abs(u) > 1e-4: - h = (57.29577951308232087721 * math.atan2(v, u) + 360.0) % 360.0 # Rad2Deg - else: - h = 0.0 - - var l = L - var c = math.sqrt(sq(u) + sq(v)) - - return l, c, h - - -fn xyz_to_linear_rgb(x: Float64, y: Float64, z: Float64) -> (Float64, Float64, Float64): - """Converts from CIE XYZ-space to Linear Color space.""" - var r = (3.2409699419045214 * x) - (1.5373831775700935 * y) - (0.49861076029300328 * z) - var g = (-0.96924363628087983 * x) + (1.8759675015077207 * y) + (0.041555057407175613 * z) - var b = (0.055630079696993609 * x) - (0.20397695888897657 * y) + (1.0569715142428786 * z) - - return r, g, b - - -fn delinearize(v: Float64) -> Float64: - if v <= 0.0031308: - return 12.92 * v - - return 1.055 * (v ** (1.0 / 2.4)) - 0.055 - - -fn linear_rgb(r: Float64, g: Float64, b: Float64) -> Color: - return Color(delinearize(r), delinearize(g), delinearize(b)) - - -fn xyz(x: Float64, y: Float64, z: Float64) -> Color: - var r: Float64 - var g: Float64 - var b: Float64 - - r, g, b = xyz_to_linear_rgb(x, y, z) - return linear_rgb(r, g, b) diff --git a/external/hue/color_gens.mojo b/external/hue/color_gens.mojo deleted file mode 100644 index 36c9e06..0000000 --- a/external/hue/color_gens.mojo +++ /dev/null @@ -1,60 +0,0 @@ -from random import randn_float64 -from .color import Color, hsv, hcl - -# Various ways to generate single random colors - - -fn fast_warm_color() -> Color: - """Creates a random dark, "warm" color through a restricted HSV space.""" - return hsv( - randn_float64() * 360.0, - 0.5 + randn_float64() * 0.3, - 0.3 + randn_float64() * 0.3, - ) - - -fn warm_color() -> Color: - """Creates a random dark, "warm" color through restricted HCL space. - This is slower than FastWarmColor but will likely give you colors which have - the same "warmness" if you run it many times.""" - var c = random_warm() - while not c.is_valid(): - c = random_warm() - - return c - - -fn random_warm() -> Color: - return hcl( - randn_float64() * 360.0, - 0.1 + randn_float64() * 0.3, - 0.2 + randn_float64() * 0.3, - ) - - -fn fast_happy_color() -> Color: - """Creates a random bright, "pimpy" color through a restricted HSV space.""" - return hsv( - randn_float64() * 360.0, - 0.7 + randn_float64() * 0.3, - 0.6 + randn_float64() * 0.3, - ) - - -fn happy_color() -> Color: - """Creates a random bright, "pimpy" color through restricted HCL space. - This is slower than FastHappyColor but will likely give you colors which - have the same "brightness" if you run it many times.""" - var c = random_pimp() - while not c.is_valid(): - c = random_pimp() - - return c - - -fn random_pimp() -> Color: - return hcl( - randn_float64() * 360.0, - 0.5 + randn_float64() * 0.3, - 0.5 + randn_float64() * 0.3, - ) diff --git a/external/hue/happy_palettegen.mojo b/external/hue/happy_palettegen.mojo deleted file mode 100644 index e468418..0000000 --- a/external/hue/happy_palettegen.mojo +++ /dev/null @@ -1,34 +0,0 @@ -from random import randn_float64 -from .color import Color, hsv, lab_to_hcl -from .soft_palettegen import soft_palette_ex, SoftPaletteSettings - - -fn fast_happy_palette(colors_count: Int) -> List[Color]: - """Uses the HSV color space to generate colors with similar S,V but distributed - evenly along their Hue. This is fast but not always pretty. - If you've got time to spare, use Lab (the non-fast below).""" - var colors = List[Color](capacity=colors_count) - for _ in range(colors_count): - colors.append(Color(0, 0, 0)) - - var i = 0 - while i < colors_count: - colors[i] = hsv( - Float64(i) * (360.0 / Float64(colors_count)), - 0.8 + randn_float64() * 0.2, - 0.65 + randn_float64() * 0.2, - ) - i += 1 - - return colors - - -fn happy_palette(colors_count: Int) raises -> List[Color]: - fn pimpy(l: Float64, a: Float64, b: Float64) -> Bool: - var h: Float64 - var c: Float64 - var l_new: Float64 - l_new, c, h = lab_to_hcl(l, a, b) - return 0.3 <= c and 0.4 <= l and l <= 0.8 - - return soft_palette_ex(colors_count, SoftPaletteSettings(pimpy, 50, True)) diff --git a/external/hue/hsluv.mojo b/external/hue/hsluv.mojo deleted file mode 100644 index 4097d12..0000000 --- a/external/hue/hsluv.mojo +++ /dev/null @@ -1,278 +0,0 @@ -from .math import cube, clamp01, sq, pi, max_float64 -from .color import Color, linear_rgb, xyz_to_linear_rgb, luv_to_xyz_white_ref -import math - -alias hSLuvD65 = List[Float64](0.95045592705167, 1.0, 1.089057750759878) - - -fn LuvLCh_to_HSLuv(l: Float64, c: Float64, h: Float64) -> (Float64, Float64, Float64): - """[-1..1] but the code expects it to be [-100..100].""" - var c_new = c * 100.0 - var l_new = l * 100.0 - - var s: Float64 - var max_val: Float64 - if l_new > 99.9999999 or l_new < 0.00000001: - s = 0.0 - else: - max_val = max_chroma_for_lh(l_new, h) - s = c_new / max_val * 100.0 - - return h, clamp01(s / 100.0), clamp01(l_new / 100.0) - - -fn HSLuvToLuvLCh(h: Float64, s: Float64, l: Float64) -> (Float64, Float64, Float64): - var tmp_l = l * 100.0 - var tmp_s = s * 100.0 - - var c: Float64 - var max: Float64 - if tmp_l > 99.9999999 or tmp_l < 0.00000001: - c = 0.0 - else: - max = max_chroma_for_lh(l, h) - c = max / 100.0 * tmp_s - - # c is [-100..100], but for LCh it's supposed to be almost [-1..1] - return clamp01(l / 100.0), c / 100.0, h - - -fn LuvLCh_to_Luv(l: Float64, c: Float64, h: Float64) -> (Float64, Float64, Float64): - var H: Float64 = 0.01745329251994329576 * h # Deg2Rad - var u = c * math.cos(H) - var v = c * math.sin(H) - return l, u, v - - -fn LuvLCh_to_HPLuv(l: Float64, c: Float64, h: Float64) -> (Float64, Float64, Float64): - """[-1..1] but the code expects it to be [-100..100].""" - var c_new = c * 100.0 - var l_new = l * 100.0 - - var s: Float64 - var max_val: Float64 - if l_new > 99.9999999 or l_new < 0.00000001: - s = 0.0 - else: - max_val = max_safe_chroma_for_l(l_new) - s = c_new / max_val * 100.0 - - return h, s / 100.0, l_new / 100.0 - - -fn HPLuv_to_LuvLCh(h: Float64, s: Float64, l: Float64) -> (Float64, Float64, Float64): - var l_new = l * 100.0 - var s_new = s * 100.0 - - var c: Float64 - var max_val: Float64 - if l_new > 99.9999999 or l_new < 0.00000001: - c = 0.0 - else: - max_val = max_safe_chroma_for_l(l_new) - c = max_val / 100.0 * s_new - - return l_new / 100.0, c / 100.0, h - - -fn HSLuv(h: Float64, s: Float64, l: Float64) -> Color: - """Creates a new Color from values in the HSLuv color space. - Hue in [0..360], a Saturation [0..1], and a Luminance (lightness) in [0..1]. - - The returned color values are clamped (using .Clamped), so this will never output - an invalid color.""" - # HSLuv -> LuvLCh -> CIELUV -> CIEXYZ -> Linear RGB -> sRGB - var l_new: Float64 - var c: Float64 - var h_new: Float64 - l_new, c, h_new = HSLuvToLuvLCh(h, s, l) - - var L: Float64 - var u: Float64 - var v: Float64 - L, u, v = LuvLCh_to_Luv(l_new, c, h_new) - - var x: Float64 - var y: Float64 - var z: Float64 - x, y, z = luv_to_xyz_white_ref(l, u, v, hSLuvD65) - - var R: Float64 - var G: Float64 - var B: Float64 - R, G, B = xyz_to_linear_rgb(x, y, z) - return linear_rgb(R, G, B).clamped() - - -fn LuvLch_to_HSLuv(l: Float64, c: Float64, h: Float64) -> (Float64, Float64, Float64): - # [-1..1] but the code expects it to be [-100..100] - var tmp_l: Float64 = l * 100.0 - var tmp_c: Float64 = c * 100.0 - - var s: Float64 - var max_val: Float64 - if tmp_l > 99.9999999 or tmp_l < 0.00000001: - s = 0.0 - else: - max_val = max_chroma_for_lh(tmp_l, h) - s = tmp_c / max_val * 100.0 - - return h, clamp01(s / 100.0), clamp01(tmp_l / 100.0) - - -fn HPLuv(h: Float64, s: Float64, l: Float64) -> Color: - """HPLuv creates a new Color from values in the HPLuv color space. - Hue in [0..360], a Saturation [0..1], and a Luminance (lightness) in [0..1]. - - The returned color values are clamped (using .Clamped), so this will never output - an invalid color.""" - # HPLuv -> LuvLCh -> CIELUV -> CIEXYZ -> Linear RGB -> sRGB - var l_new: Float64 - var c: Float64 - var h_new: Float64 - l_new, c, h_new = HPLuv_to_LuvLCh(h, s, l) - - var L: Float64 - var u: Float64 - var v: Float64 - L, u, v = LuvLCh_to_Luv(l_new, c, h_new) - - var x: Float64 - var y: Float64 - var z: Float64 - x, y, z = luv_to_xyz_white_ref(l, u, v, hSLuvD65) - - var R: Float64 - var G: Float64 - var B: Float64 - R, G, B = xyz_to_linear_rgb(x, y, z) - return linear_rgb(R, G, B).clamped() - - -fn HSLuv(self: Color) -> (Float64, Float64, Float64): - """HSLuv returns the Hue, Saturation and Luminance of the color in the HSLuv - color space. Hue in [0..360], a Saturation [0..1], and a Luminance - (lightness) in [0..1].""" - # sRGB -> Linear RGB -> CIEXYZ -> CIELUV -> LuvLCh -> HSLuv - var l: Float64 - var c: Float64 - var h: Float64 - l, c, h = self.LuvLCh_white_ref(hSLuvD65) - - return LuvLCh_to_HSLuv(l, c, h) - - -fn HPLuv(self: Color) -> (Float64, Float64, Float64): - """HPLuv returns the Hue, Saturation and Luminance of the color in the HSLuv - color space. Hue in [0..360], a Saturation [0..1], and a Luminance - (lightness) in [0..1]. - - Note that HPLuv can only represent pastel colors, and so the Saturation - value could be much larger than 1 for colors it can't represent.""" - # sRGB -> Linear RGB -> CIEXYZ -> CIELUV -> LuvLCh -> HSLuv - var l: Float64 - var c: Float64 - var h: Float64 - l, c, h = self.LuvLCh_white_ref(hSLuvD65) - - return LuvLCh_to_HPLuv(l, c, h) - - -fn DistanceHPLuv(self: Color, other: Color) -> Float64: - """DistanceHPLuv calculates Euclidean distance in the HPLuv colorspace. No idea - how useful this is. - - The Hue value is divided by 100 before the calculation, so that H, S, and L - have the same relative ranges.""" - var h1: Float64 - var s1: Float64 - var l1: Float64 - h1, s1, l1 = self.HPLuv() - - var h2: Float64 - var s2: Float64 - var l2: Float64 - h2, s2, l2 = other.HPLuv() - - return math.sqrt(sq((h1 - h2) / 100.0) + sq(s1 - s2) + sq(l1 - l2)) - - -alias m = List[List[Float64]]( - List[Float64](3.2409699419045214, -1.5373831775700935, -0.49861076029300328), - List[Float64](-0.96924363628087983, 1.8759675015077207, 0.041555057407175613), - List[Float64](0.055630079696993609, -0.20397695888897657, 1.0569715142428786), -) - -alias kappa = 903.2962962962963 -alias epsilon = 0.0088564516790356308 - - -fn get_bounds(l: Float64) -> List[List[Float64]]: - var sub2: Float64 - var sub1 = (l + 16.0**3.0) / 1560896.0 - - var ret = List[List[Float64]]( - List[Float64](0, 0), - List[Float64](0, 0), - List[Float64](0, 0), - List[Float64](0, 0), - List[Float64](0, 0), - List[Float64](0, 0), - ) - - if sub1 > epsilon: - sub2 = sub1 - else: - sub2 = l / kappa - - for i in range(len(m)): - var k = 0 - while k < 2: - var top1 = (284517.0 * m[i][0] - 94839.0 * m[i][2]) * sub2 - var top2 = (838422.0 * m[i][2] + 769860.0 * m[i][1] + 731718.0 * m[i][0]) * l * sub2 - 769860.0 * Float64( - k - ) * l - var bottom = (632260.0 * m[i][2] - 126452.0 * m[i][1]) * sub2 + 126452.0 * Float64(k) - ret[i * 2 + k][0] = top1 / bottom - ret[i * 2 + k][1] = top2 / bottom - k += 1 - - return ret - - -fn length_of_ray_until_intersect(theta: Float64, x: Float64, y: Float64) -> Float64: - return y / (math.sin(theta) - x * math.cos(theta)) - - -fn max_chroma_for_lh(l: Float64, h: Float64) -> Float64: - var hRad = h / 360.0 * pi * 2.0 - var minLength = max_float64 - var bounds = get_bounds(l) - - for i in range(len(bounds)): - var line = bounds[i] - var length = length_of_ray_until_intersect(hRad, line[0], line[1]) - if length > 0.0 and length < minLength: - minLength = length - - return minLength - - -fn max_safe_chroma_for_l(l: Float64) -> Float64: - var min_length = max_float64 - for line in get_bounds(l): - var m1 = line[][0] - var b1 = line[][1] - var x = intersect_line_line(m1, b1, -1.0 / m1, 0.0) - var dist = distance_from_pole(x, b1 + x * m1) - if dist < min_length: - min_length = dist - return min_length - - -fn intersect_line_line(x1: Float64, y1: Float64, x2: Float64, y2: Float64) -> Float64: - return (y1 - y2) / (x2 - x1) - - -fn distance_from_pole(x: Float64, y: Float64) -> Float64: - return math.sqrt(sq(x) + sq(y)) diff --git a/external/hue/math.mojo b/external/hue/math.mojo deleted file mode 100644 index 93233fb..0000000 --- a/external/hue/math.mojo +++ /dev/null @@ -1,18 +0,0 @@ -from utils.numerics import max_finite - - -fn cube(v: Float64) -> Float64: - return v * v * v - - -fn sq(v: Float64) -> Float64: - return v * v - - -fn clamp01(v: Float64) -> Float64: - """Clamps from 0 to 1.""" - return max(0.0, min(v, 1.0)) - - -alias pi: Float64 = 3.141592653589793238462643383279502884197169399375105820974944592307816406286 -alias max_float64: Float64 = max_finite[DType.float64]() diff --git a/external/hue/soft_palettegen.mojo b/external/hue/soft_palettegen.mojo deleted file mode 100644 index af43396..0000000 --- a/external/hue/soft_palettegen.mojo +++ /dev/null @@ -1,214 +0,0 @@ -from collections.optional import Optional -from random import random_si64 -from utils.numerics import inf -import math -from .math import sq -from .color import lab - - -# The algorithm works in L*a*b* color space and converts to RGB in the end. -# L* in [0..1], a* and b* in [-1..1] -@register_passable("trivial") -struct lab_t(EqualityComparable): - var L: Float64 - var A: Float64 - var B: Float64 - - fn __init__(inout self, L: Float64, A: Float64, B: Float64): - self.L = L - self.A = A - self.B = B - - fn __eq__(self, other: lab_t) -> Bool: - return self.L == other.L and self.A == other.A and self.B == other.B - - fn __ne__(self, other: lab_t) -> Bool: - return self.L != other.L or self.A != other.A or self.B != other.B - - -fn in_stack(haystack: List[lab_t], upto: Int, needle: lab_t) -> Bool: - var i = 0 - while i < upto and i < len(haystack): - if haystack[i] == needle: - return True - i += 1 - - return False - - -fn labs_2_cols(labs: List[lab_t]) -> List[Color]: - var lab_count = len(labs) - var cols = List[Color](capacity=lab_count) - for _ in range(lab_count): - cols.append(Color(0.0, 0.0, 0.0)) - - for i in range(lab_count): - cols[i] = lab(labs[i].L, labs[i].A, labs[i].B) - - return cols - - -alias CheckColorFn = fn (l: Float64, a: Float64, b: Float64) -> Bool - - -@value -struct SoftPaletteSettings: - # A fntion which can be used to restrict the allowed color-space. - var check_color: Optional[CheckColorFn] - - # The higher, the better quality but the slower. Usually two figures. - var iterations: Int - - # Use up to 160000 or 8000 samples of the L*a*b* space (and thus calls to CheckColor). - # Set this to true only if your CheckColor shapes the Lab space weirdly. - var many_samples: Bool - - -# That's faster than using colorful's DistanceLab since we would have to -# convert back and forth for that. Here is no conversion. -fn lab_dist(lab1: lab_t, lab2: lab_t) -> Float64: - return math.sqrt(sq(lab1.L - lab2.L) + sq(lab1.A - lab2.A) + sq(lab1.B - lab2.B)) - - -# A wrapper which uses common parameters. -fn soft_palette(colors_count: Int) raises -> List[Color]: - return soft_palette_ex(colors_count, SoftPaletteSettings(None, 50, False)) - - -alias LAB_DELTA = 1e-6 - - -fn lab_eq(lab1: lab_t, lab2: lab_t) -> Bool: - return abs(lab1.L - lab2.L) < LAB_DELTA and abs(lab1.A - lab2.A) < LAB_DELTA and abs(lab1.B - lab2.B) < LAB_DELTA - - -fn soft_palette_ex(colors_count: Int, settings: SoftPaletteSettings) raises -> List[Color]: - """Yeah, windows-stype Foo, FooEx, screw you golang... - Uses K-means to cluster the color-space and return the means of the clusters - as a new palette of distinctive colors. Falls back to K-medoid if the mean - happens to fall outside of the color-space, which can only happen if you - specify a CheckColor fntion.""" - - # Checks whether it's a valid RGB and also fulfills the potentially provided constraint. - @always_inline - fn check(col: lab_t) -> Bool: - var c = lab(col.L, col.A, col.B) - return c.is_valid() and settings.check_color.value()[](col.L, col.A, col.B) - - # Sample the color space. These will be the points k-means is run on. - var dl = 0.05 - var dab = 0.1 - if settings.many_samples: - dl = 0.01 - dab = 0.05 - - var samples = List[lab_t](capacity=int(1.0 / dl * 2.0 / dab * 2.0 / dab)) - var l = 0.0 - while l <= 1.0: - var a = -1.0 - while a <= 1.0: - var b = -1.0 - while b <= 1.0: - var labt = lab_t(l, a, b) - if check(labt): - samples.append(labt) - b += dab - a += dab - l += dl - - # That would cause some infinite loops down there... - if len(samples) < colors_count: - raise Error( - String("palettegen: more colors requested ") - + str(colors_count) - + " than samples available " - + str(len(samples)) - + " Your requested color count may be wrong, you might want to use" - " many samples or your constraint fntion makes the valid color" - " space too small" - ) - elif len(samples) == colors_count: - return labs_2_cols(samples) # Oops? - - # We take the initial means out of the samples, so they are in fact medoids. - # This helps us avoid infinite loops or arbitrary cutoffs with too restrictive constraints. - var means = List[lab_t](capacity=colors_count) - for _ in range(colors_count): - means.append(lab_t(0.0, 0.0, 0.0)) - - var i = 0 - while i < colors_count: - i += 1 - means[i] = samples[int(random_si64(0, len(samples)))] - while in_stack(means, i, means[i]): - means[i] = samples[int(random_si64(0, len(samples)))] - - var clusters = List[Int](capacity=len(samples)) - for _ in range(len(samples)): - clusters.append(0) - var samples_used = List[Bool](capacity=len(samples)) - for _ in range(len(samples)): - samples_used.append(False) - - # The actual k-means/medoid iterations - i = 0 - while i < settings.iterations: - # Reassing the samples to clusters, i.e. to their closest mean. - # By the way, also check if any sample is used as a medoid and if so, mark that. - for j in range(len(samples)): - samples_used[j] = False - var mindist = inf[DType.float64]() - for k in range(len(means)): - var dist = lab_dist(samples[j], means[k]) - if dist < mindist: - mindist = dist - clusters[j] = k - - # Mark samples which are used as a medoid. - if lab_eq(samples[j], means[k]): - samples_used[i] = True - - # Compute new means according to the samples. - for k in range(len(means)): - # The new mean is the average of all samples belonging to it.. - var nsamples = 0 - var newmean = lab_t(0.0, 0.0, 0.0) - - for j in range(len(samples)): - if clusters[j] == k: - nsamples += 1 - newmean.L += samples[j].L - newmean.A += samples[j].A - newmean.B += samples[j].B - - if nsamples > 0: - newmean.L /= Float64(nsamples) - newmean.A /= Float64(nsamples) - newmean.B /= Float64(nsamples) - else: - # That mean doesn't have any samples? Get a new mean from the sample list! - var inewmean = int(random_si64(0, len(samples_used))) - while samples_used[inewmean]: - inewmean = int(random_si64(0, len(samples_used))) - - newmean = samples[inewmean] - samples_used[inewmean] = True - - # But now we still need to check whether the new mean is an allowed color. - if nsamples > 0 and check(newmean): - # It does, life's good (TM) - means[k] = newmean - else: - # New mean isn't an allowed color or doesn't have any samples! - # Switch to medoid mode and pick the closest (unused) sample. - # This should always find something thanks to len(samples) >= colors_count - var mindist = inf[DType.float64]() - for l in range(len(samples)): - if not samples_used[l]: - var dist = lab_dist(samples[l], newmean) - if dist < mindist: - mindist = dist - newmean = samples[l] - i += 1 - - return labs_2_cols(means) diff --git a/external/hue/sort.mojo b/external/hue/sort.mojo deleted file mode 100644 index 3be3d88..0000000 --- a/external/hue/sort.mojo +++ /dev/null @@ -1,178 +0,0 @@ -# # An element represents a single element of a set. It is used to -# # implement a disjoint-set forest. -# type element struct: -# parent *element # Parent element -# rank int # Rank (approximate depth) of the subtree with this element as root - - -# # newElement creates a singleton set and returns its sole element. -# fn newElement() *element: -# s = &element{ -# s.parent = s -# return s - - -# # find returns an arbitrary element of a set when invoked on any element of -# # the set, The important feature is that it returns the same value when -# # invoked on any element of the set. Consequently, it can be used to test if -# # two elements belong to the same set. -# fn (e *element) find() *element: -# for e.parent != e: -# e.parent = e.parent.parent -# e = e.parent - -# return e - - -# # union establishes the union of two sets when given an element from each set. -# # Afterwards, the original sets no longer exist as separate entities. -# fn union(e1, e2 *element): -# # Ensure the two elements aren't already part of the same union. -# e1Root = e1.find() -# e2Root = e2.find() -# if e1Root == e2Root: -# return - - -# # Create a union by making the shorter tree point to the root of the -# # larger tree. -# switch: -# case e1Root.rank < e2Root.rank: -# e1Root.parent = e2Root -# case e1Root.rank > e2Root.rank: -# e2Root.parent = e1Root -# default: -# e2Root.parent = e1Root -# e1Root.rank++ - - -# # An edgeIdxs describes an edge in a graph or tree. The vertices in the edge -# # are indexes into a list of Color values. -# type edgeIdxs [2]int - -# # An edgeDistance is a map from an edge (pair of indices) to a distance -# # between the two vertices. -# type edgeDistance map[edgeIdxs]float64 - -# # allToAllDistancesCIEDE2000 computes the CIEDE2000 distance between each pair of -# # colors. It returns a map from a pair of indices (u, v) with u < v to a -# # distance. -# fn allToAllDistancesCIEDE2000(cs []Color) edgeDistance: -# nc = len(cs) -# m = make(edgeDistance, nc*nc) -# for u = 0; u < nc-1; u++: -# for v = u + 1; v < nc; v++: -# m[edgeIdxs{u, v] = cs[u].DistanceCIEDE2000(cs[v]) - - -# return m - - -# # sortEdges sorts all edges in a distance map by increasing vertex distance. -# fn sortEdges(m edgeDistance) []edgeIdxs: -# es = make([]edgeIdxs, 0, len(m)) -# for uv = range m: -# es = append(es, uv) - -# sort.Slice(es, fn(i, j int) bool: -# return m[es[i]] < m[es[j]] -# ) -# return es - - -# # minSpanTree computes a minimum spanning tree from a vertex count and a -# # distance-sorted edge list. It returns the subset of edges that belong to -# # the tree, including both (u, v) and (v, u) for each edge. -# fn minSpanTree(nc int, es []edgeIdxs) map[edgeIdxs]struct{: -# # Start with each vertex in its own set. -# elts = make([]*element, nc) -# for i = range elts: -# elts[i] = newElement() - - -# # Run Kruskal's algorithm to construct a minimal spanning tree. -# mst = make(map[edgeIdxs]struct{, nc) -# for _, uv = range es: -# u, v = uv[0], uv[1] -# if elts[u].find() == elts[v].find(): -# continue # Same set: edge would introduce a cycle. - -# mst[uv] = struct{{ -# mst[edgeIdxs{v, u] = struct{{ -# union(elts[u], elts[v]) - -# return mst - - -# # traverseMST walks a minimum spanning tree in prefix order. -# fn traverseMST(mst map[edgeIdxs]struct{, root int) []int: -# # Compute a list of neighbors for each vertex. -# neighs = make(map[int][]int, len(mst)) -# for uv = range mst: -# u, v = uv[0], uv[1] -# neighs[u] = append(neighs[u], v) - -# for u, vs = range neighs: -# sort.Ints(vs) -# copy(neighs[u], vs) - - -# # Walk the tree from a given vertex. -# order = make([]int, 0, len(neighs)) -# visited = make(map[int]bool, len(neighs)) -# var walkFrom fn(int) -# walkFrom = fn(r int): -# # Visit the starting vertex. -# order = append(order, r) -# visited[r] = true - -# # Recursively visit each child in turn. -# for _, c = range neighs[r]: -# if !visited[c]: -# walkFrom(c) - - -# walkFrom(root) -# return order - - -# # Sorted sorts a list of Color values. Sorting is not a well-defined operation -# # for colors so the intention here primarily is to order colors so that the -# # transition from one to the next is fairly smooth. -# fn Sorted(cs []Color) []Color: -# # Do nothing in trivial cases. -# newCs = make([]Color, len(cs)) -# if len(cs) < 2: -# copy(newCs, cs) -# return newCs - - -# # Compute the distance from each color to every other color. -# dists = allToAllDistancesCIEDE2000(cs) - -# # Produce a list of edges in increasing order of the distance between -# # their vertices. -# edges = sortEdges(dists) - -# # Construct a minimum spanning tree from the list of edges. -# mst = minSpanTree(len(cs), edges) - -# # Find the darkest color in the list. -# var black Color -# var dIdx int # Index of darkest color -# light = math.MaxFloat64 # Lightness of darkest color (distance from black) -# for i, c = range cs: -# d = black.DistanceCIEDE2000(c) -# if d < light: -# dIdx = i -# light = d - - -# # Traverse the tree starting from the darkest color. -# idxs = traverseMST(mst, dIdx) - -# # Convert the index list to a list of colors, overwriting the input. -# for i, idx = range idxs: -# newCs[i] = cs[idx] - -# return newCs diff --git a/external/hue/warm_palettegen.mojo b/external/hue/warm_palettegen.mojo deleted file mode 100644 index c8b04cd..0000000 --- a/external/hue/warm_palettegen.mojo +++ /dev/null @@ -1,41 +0,0 @@ -from random import randn_float64 -from .color import hsv, lab_to_hcl -from .soft_palettegen import soft_palette_ex, SoftPaletteSettings - - -fn fast_warm_palette(colors_count: Int) -> List[Color]: - """Uses the hsv color space to generate colors with similar S,V but distributed - evenly along their Hue. This is fast but not always pretty. - If you've got time to spare, use Lab (the non-fast below). - - Args: - colors_count: The number of colors to generate. - - Returns: - A list of colors. - """ - var colors = List[Color](capacity=colors_count) - for _ in range(colors_count): - colors.append(Color(0, 0, 0)) - - var i = 0 - while i < colors_count: - colors[i] = hsv( - Float64(i) * (360.0 / Float64(colors_count)), - 0.55 + randn_float64() * 0.2, - 0.35 + randn_float64() * 0.2, - ) - i += 1 - - return colors - - -fn warm_palette(colors_count: Int) raises -> List[Color]: - fn warmy(l: Float64, a: Float64, b: Float64) -> Bool: - var h: Float64 - var c: Float64 - var l_new: Float64 - h, c, l_new = lab_to_hcl(l, a, b) - return 0.1 <= c and c <= 0.4 and 0.2 <= l and l <= 0.5 - - return soft_palette_ex(colors_count, SoftPaletteSettings(warmy, 50, True)) diff --git a/external/mist/__init__.mojo b/external/mist/__init__.mojo deleted file mode 100644 index 915cb0e..0000000 --- a/external/mist/__init__.mojo +++ /dev/null @@ -1,39 +0,0 @@ -from .color import Color -from .style import Style, new_style -from .profile import ( - Profile, - ASCII, - ANSI, - ANSI256, - TRUE_COLOR, - ASCII_PROFILE, - ANSI_PROFILE, - ANSI256_PROFILE, - TRUE_COLOR_PROFILE, - AnyColor, - NoColor, -) -from .renderers import ( - render_as_color, - render_with_background_color, - red, - green, - blue, - yellow, - cyan, - gray, - magenta, - red_background, - green_background, - blue_background, - yellow_background, - cyan_background, - gray_background, - magenta_background, - bold, - italic, - underline, - faint, - crossout, - overline, -) diff --git a/external/mist/ansi_colors.mojo b/external/mist/ansi_colors.mojo deleted file mode 100644 index 421c727..0000000 --- a/external/mist/ansi_colors.mojo +++ /dev/null @@ -1,259 +0,0 @@ -alias ANSI_HEX_CODES = List[UInt32]( - 0x000000, - 0x800000, - 0x008000, - 0x808000, - 0x000080, - 0x800080, - 0x008080, - 0xC0C0C0, - 0x808080, - 0xFF0000, - 0x00FF00, - 0xFFFF00, - 0x0000FF, - 0xFF00FF, - 0x00FFFF, - 0xFFFFFF, - 0x000000, - 0x00005F, - 0x000087, - 0x0000AF, - 0x0000D7, - 0x0000FF, - 0x005F00, - 0x005F5F, - 0x005F87, - 0x005FAF, - 0x005FD7, - 0x005FFF, - 0x008700, - 0x00875F, - 0x008787, - 0x0087AF, - 0x0087D7, - 0x0087FF, - 0x00AF00, - 0x00AF5F, - 0x00AF87, - 0x00AFAF, - 0x00AFD7, - 0x00AFFF, - 0x00D700, - 0x00D75F, - 0x00D787, - 0x00D7AF, - 0x00D7D7, - 0x00D7FF, - 0x00FF00, - 0x00FF5F, - 0x00FF87, - 0x00FFAF, - 0x00FFD7, - 0x00FFFF, - 0x5F0000, - 0x5F005F, - 0x5F0087, - 0x5F00AF, - 0x5F00D7, - 0x5F00FF, - 0x5F5F00, - 0x5F5F5F, - 0x5F5F87, - 0x5F5FAF, - 0x5F5FD7, - 0x5F5FFF, - 0x5F8700, - 0x5F875F, - 0x5F8787, - 0x5F87AF, - 0x5F87D7, - 0x5F87FF, - 0x5FAF00, - 0x5FAF5F, - 0x5FAF87, - 0x5FAFAF, - 0x5FAFD7, - 0x5FAFFF, - 0x5FD700, - 0x5FD75F, - 0x5FD787, - 0x5FD7AF, - 0x5FD7D7, - 0x5FD7FF, - 0x5FFF00, - 0x5FFF5F, - 0x5FFF87, - 0x5FFFAF, - 0x5FFFD7, - 0x5FFFFF, - 0x870000, - 0x87005F, - 0x870087, - 0x8700AF, - 0x8700D7, - 0x8700FF, - 0x875F00, - 0x875F5F, - 0x875F87, - 0x875FAF, - 0x875FD7, - 0x875FFF, - 0x878700, - 0x87875F, - 0x878787, - 0x8787AF, - 0x8787D7, - 0x8787FF, - 0x87AF00, - 0x87AF5F, - 0x87AF87, - 0x87AFAF, - 0x87AFD7, - 0x87AFFF, - 0x87D700, - 0x87D75F, - 0x87D787, - 0x87D7AF, - 0x87D7D7, - 0x87D7FF, - 0x87FF00, - 0x87FF5F, - 0x87FF87, - 0x87FFAF, - 0x87FFD7, - 0x87FFFF, - 0xAF0000, - 0xAF005F, - 0xAF0087, - 0xAF00AF, - 0xAF00D7, - 0xAF00FF, - 0xAF5F00, - 0xAF5F5F, - 0xAF5F87, - 0xAF5FAF, - 0xAF5FD7, - 0xAF5FFF, - 0xAF8700, - 0xAF875F, - 0xAF8787, - 0xAF87AF, - 0xAF87D7, - 0xAF87FF, - 0xAFAF00, - 0xAFAF5F, - 0xAFAF87, - 0xAFAFAF, - 0xAFAFD7, - 0xAFAFFF, - 0xAFD700, - 0xAFD75F, - 0xAFD787, - 0xAFD7AF, - 0xAFD7D7, - 0xAFD7FF, - 0xAFFF00, - 0xAFFF5F, - 0xAFFF87, - 0xAFFFAF, - 0xAFFFD7, - 0xAFFFFF, - 0xD70000, - 0xD7005F, - 0xD70087, - 0xD700AF, - 0xD700D7, - 0xD700FF, - 0xD75F00, - 0xD75F5F, - 0xD75F87, - 0xD75FAF, - 0xD75FD7, - 0xD75FFF, - 0xD78700, - 0xD7875F, - 0xD78787, - 0xD787AF, - 0xD787D7, - 0xD787FF, - 0xD7AF00, - 0xD7AF5F, - 0xD7AF87, - 0xD7AFAF, - 0xD7AFD7, - 0xD7AFFF, - 0xD7D700, - 0xD7D75F, - 0xD7D787, - 0xD7D7AF, - 0xD7D7D7, - 0xD7D7FF, - 0xD7FF00, - 0xD7FF5F, - 0xD7FF87, - 0xD7FFAF, - 0xD7FFD7, - 0xD7FFFF, - 0xFF0000, - 0xFF005F, - 0xFF0087, - 0xFF00AF, - 0xFF00D7, - 0xFF00FF, - 0xFF5F00, - 0xFF5F5F, - 0xFF5F87, - 0xFF5FAF, - 0xFF5FD7, - 0xFF5FFF, - 0xFF8700, - 0xFF875F, - 0xFF8787, - 0xFF87AF, - 0xFF87D7, - 0xFF87FF, - 0xFFAF00, - 0xFFAF5F, - 0xFFAF87, - 0xFFAFAF, - 0xFFAFD7, - 0xFFAFFF, - 0xFFD700, - 0xFFD75F, - 0xFFD787, - 0xFFD7AF, - 0xFFD7D7, - 0xFFD7FF, - 0xFFFF00, - 0xFFFF5F, - 0xFFFF87, - 0xFFFFAF, - 0xFFFFD7, - 0xFFFFFF, - 0x080808, - 0x121212, - 0x1C1C1C, - 0x262626, - 0x303030, - 0x3A3A3A, - 0x444444, - 0x4E4E4E, - 0x585858, - 0x626262, - 0x6C6C6C, - 0x767676, - 0x808080, - 0x8A8A8A, - 0x949494, - 0x9E9E9E, - 0xA8A8A8, - 0xB2B2B2, - 0xBCBCBC, - 0xC6C6C6, - 0xD0D0D0, - 0xDADADA, - 0xE4E4E4, - 0xEEEEEE, -) -"""RGB values of ANSI colors (0-255).""" diff --git a/external/mist/color.mojo b/external/mist/color.mojo deleted file mode 100644 index fce0ecb..0000000 --- a/external/mist/color.mojo +++ /dev/null @@ -1,326 +0,0 @@ -import external.hue -from .ansi_colors import ANSI_HEX_CODES - - -# Workaround for str() not working at compile time due to using an external_call to c. -fn int_to_str(owned value: Int, base: Int = 10) -> String: - """Converts an integer to a string. - - Args: - value: The integer to convert to a string. - base: The base to convert the integer to. - - Returns: - The string representation of the integer. - """ - # Catch edge case of 0 - if value == 0: - return "0" - - var temp = List[UInt8]() - var i = 0 - while value > 0: - temp.append(ord(String("0123456789abcdef")[value % base])) - i += 1 - value /= 10 - - var buffer = List[UInt8]() - for i in range(len(temp) - 1, -1, -1): - buffer.append(temp[i]) - - buffer.append(0) - var result = String(buffer^) - return result - - -alias FOREGROUND = "38" -alias BACKGROUND = "48" -alias AnyColor = Variant[NoColor, ANSIColor, ANSI256Color, RGBColor] - - -trait Color(EqualityComparable, CollectionElement): - fn sequence(self, is_background: Bool) -> String: - """Sequence returns the ANSI Sequence for the color.""" - ... - - -@register_passable("trivial") -struct NoColor(Color, Stringable): - fn __init__(inout self): - pass - - fn __eq__(self, other: NoColor) -> Bool: - return True - - fn __ne__(self, other: NoColor) -> Bool: - return False - - fn sequence(self, is_background: Bool) -> String: - return "" - - fn __str__(self) -> String: - """String returns the ANSI Sequence for the color and the text.""" - return "" - - -@register_passable("trivial") -struct ANSIColor(Color, Stringable): - """ANSIColor is a color (0-15) as defined by the ANSI Standard.""" - - var value: UInt32 - - fn __init__(inout self, value: UInt32): - self.value = value - - fn __eq__(self, other: ANSIColor) -> Bool: - return self.value == other.value - - fn __ne__(self, other: ANSIColor) -> Bool: - return self.value != other.value - - fn sequence(self, is_background: Bool) -> String: - """Returns the ANSI Sequence for the color and the text. - - Args: - is_background: Whether the color is a background color. - """ - var modifier: Int = 0 - if is_background: - modifier += 10 - - if self.value < 8: - return int_to_str(modifier + int(self.value) + 30) - return int_to_str(modifier + int(self.value) - 8 + 90) - - fn __str__(self) -> String: - """String returns the ANSI Sequence for the color and the text.""" - return ANSI_HEX_CODES[int(self.value)] - - -@register_passable("trivial") -struct ANSI256Color(Color, Stringable): - """ANSI256Color is a color (16-255) as defined by the ANSI Standard.""" - - var value: UInt32 - - fn __init__(inout self, value: UInt32): - self.value = value - - fn __eq__(self, other: ANSI256Color) -> Bool: - return self.value == other.value - - fn __ne__(self, other: ANSI256Color) -> Bool: - return self.value != other.value - - fn sequence(self, is_background: Bool) -> String: - """Returns the ANSI Sequence for the color and the text. - - Args: - is_background: Whether the color is a background color. - """ - var prefix: String = FOREGROUND - if is_background: - prefix = BACKGROUND - - return prefix + ";5;" + int_to_str(int(self.value)) - - fn __str__(self) -> String: - """String returns the ANSI Sequence for the color and the text.""" - return ANSI_HEX_CODES[int(self.value)] - - -# // ansiToRGB converts an ANSI color to a 24-bit RGB color. -# // -# // r, g, b := ansiToRGB(57) -# func ansiToRGB(ansi uint32) (uint32, uint32, uint32) { -# // For out-of-range values return black. -# if ansi > 255 { -# return 0, 0, 0 -# } - -# // Low ANSI. -# if ansi < 16 { -# h, ok := lowANSI[ansi] -# if !ok { -# return 0, 0, 0 -# } -# r, g, b := hexToRGB(h) -# return r, g, b -# } - -# // Grays. -# if ansi > 231 { -# s := (ansi-232)*10 + 8 -# return s, s, s -# } - -# // ANSI256. -# n := ansi - 16 -# b := n % 6 -# g := (n - b) / 6 % 6 -# r := (n - b - g*6) / 36 % 6 -# for _, v := range []*uint32{&r, &g, &b} { -# if *v > 0 { -# c := *v*40 + 55 -# *v = c -# } -# } - -# return r, g, b -# } - - -fn ansi_to_rgb(ansi: UInt32) -> (UInt32, UInt32, UInt32): - """Converts an ANSI color to a 24-bit RGB color.""" - # For out-of-range values return black. - if ansi > 255: - return UInt32(0), UInt32(0), UInt32(0) - - # Low ANSI. - if ansi < 16: - var h = ANSI_HEX_CODES[int(ansi)] - return hex_to_rgb(h) - - # Grays. - if ansi > 231: - var s = (ansi - 232) * 10 + 8 - return s, s, s - - # ANSI256. - var n = ansi - 16 - var b = n % 6 - var g = (n - b) / 6 % 6 - var r = (n - b - g * 6) / 36 % 6 - var rgb = List[UInt32](r, g, b) - var v = rgb[0] - var i = 0 - while i < 3: - if v > 0: - var c = v * 40 + 55 - v = c - i += 1 - - return r, g, b - - -fn hex_to_rgb(hex: UInt32) -> (UInt32, UInt32, UInt32): - """Converts a number in hexadecimal format to red, green, and blue values. - - `r, g, b = hex_to_rgb(0x0000FF)`. - """ - return hex >> 16, hex >> 8 & 0xFF, hex & 0xFF - - -@register_passable("trivial") -struct RGBColor(Color): - """RGBColor is a hex-encoded color, e.g. '#abcdef'.""" - - var value: UInt32 - - fn __init__(inout self, value: UInt32): - self.value = value - - fn __eq__(self, other: RGBColor) -> Bool: - return self.value == other.value - - fn __ne__(self, other: RGBColor) -> Bool: - return self.value != other.value - - fn sequence(self, is_background: Bool) -> String: - """Returns the ANSI Sequence for the color and the text. - - Args: - is_background: Whether the color is a background color. - """ - var rgb = hex_to_rgb(self.value) - - var prefix = FOREGROUND - if is_background: - prefix = BACKGROUND - - return ( - prefix - + String(";2;") - + int_to_str(int(rgb[0])) - + ";" - + int_to_str(int(rgb[1])) - + ";" - + int_to_str(int(rgb[2])) - ) - - -fn ansi256_to_ansi(value: UInt32) -> ANSIColor: - """Converts an ANSI256 color to an ANSI color. - - Args: - value: ANSI256 color value. - """ - var r: Int = 0 - var md = hue.math.max_float64 - - var h = hex_to_rgb(ANSI_HEX_CODES[int(value)]) - - var i: Int = 0 - while i <= 15: - var hb = hex_to_rgb(ANSI_HEX_CODES[int(i)]) - var d = hue.Color( - h[0].cast[DType.float64](), h[1].cast[DType.float64](), h[2].cast[DType.float64]() - ).distance_HSLuv( - hue.Color(hb[0].cast[DType.float64](), hb[1].cast[DType.float64](), hb[2].cast[DType.float64]()) - ) - - if d < md: - md = d - r = i - - i += 1 - - return ANSIColor(r) - - -fn v2ci(value: Float64) -> Int: - if value < 48: - return 0 - elif value < 115: - return 1 - return int((value - 35) / 40) - - -fn hex_to_ansi256(color: hue.Color) -> ANSI256Color: - """Converts a hex code to a ANSI256 color. - - Args: - color: Hex code color from hue.Color. - """ - # Calculate the nearest 0-based color index at 16..231 - # Originally had * 255 in each of these - var r: Float64 = v2ci(color.R) # 0..5 each - var g: Float64 = v2ci(color.G) - var b: Float64 = v2ci(color.B) - var ci: Int = int((36 * r) + (6 * g) + b) # 0..215 - - # Calculate the represented colors back from the index - alias i2cv = InlineArray[Int, 6](0, 0x5F, 0x87, 0xAF, 0xD7, 0xFF) - var cr = i2cv[int(r)] # r/g/b, 0..255 each - var cg = i2cv[int(g)] - var cb = i2cv[int(b)] - - # Calculate the nearest 0-based gray index at 232..255 - var gray_index: Int - var average = (r + g + b) / 3 - if average > 238: - gray_index = 23 - else: - gray_index = int((average - 3) / 10) # 0..23 - var gv = 8 + 10 * gray_index # same value for r/g/b, 0..255 - - # Return the one which is nearer to the original input rgb value - # Originall had / 255.0 for r, g, and b in each of these - var c2 = hue.Color(cr, cg, cb) - var g2 = hue.Color(gv, gv, gv) - var color_dist = color.distance_HSLuv(c2) - var gray_dist = color.distance_HSLuv(g2) - - if color_dist <= gray_dist: - return ANSI256Color(16 + ci) - return ANSI256Color(232 + gray_index) diff --git a/external/mist/hyperlink.mojo b/external/mist/hyperlink.mojo deleted file mode 100644 index 56e0c8c..0000000 --- a/external/mist/hyperlink.mojo +++ /dev/null @@ -1,14 +0,0 @@ -from .style import osc, st - - -fn hyperlink(link: String, name: String) -> String: - """Creates a hyperlink using OSC8. - - Args: - link: The URL to link to. - name: The text to display. - - Returns: - The hyperlink text. - """ - return osc + "8;;" + link + st + name + osc + "8;;" + st diff --git a/external/mist/notification.mojo b/external/mist/notification.mojo deleted file mode 100644 index 10135cf..0000000 --- a/external/mist/notification.mojo +++ /dev/null @@ -1,11 +0,0 @@ -from .style import osc, st - - -fn notify(title: String, body: String): - """Sends a notification to the terminal. - - Args: - title: The title of the notification. - body: The body of the notification. - """ - print(osc + "777;notify;" + title + ";" + body + st, end="") diff --git a/external/mist/profile.mojo b/external/mist/profile.mojo deleted file mode 100644 index b2abc24..0000000 --- a/external/mist/profile.mojo +++ /dev/null @@ -1,149 +0,0 @@ -import os -import external.hue -from .color import ( - NoColor, - ANSIColor, - ANSI256Color, - RGBColor, - AnyColor, - hex_to_ansi256, - ansi256_to_ansi, - hex_to_rgb, - ansi_to_rgb, - int_to_str, -) - -alias TRUE_COLOR: Int = 0 -alias ANSI256: Int = 1 -alias ANSI: Int = 2 -alias ASCII: Int = 3 - -alias TRUE_COLOR_PROFILE = Profile(TRUE_COLOR) -alias ANSI256_PROFILE = Profile(ANSI256) -alias ANSI_PROFILE = Profile(ANSI) -alias ASCII_PROFILE = Profile(ASCII) - - -# TODO: UNIX systems only for now. Need to add Windows, POSIX, and SOLARIS support. -fn get_color_profile() -> Int: - """Queries the terminal to determine the color profile it supports. - ASCII, ANSI, ANSI256, or TRUE_COLOR. - """ - # if not o.isTTY(): - # return Ascii - if os.getenv("GOOGLE_CLOUD_SHELL", "false") == "true": - return TRUE_COLOR - - var term = os.getenv("TERM").lower() - var color_term = os.getenv("COLORTERM").lower() - - # COLORTERM is used by some terminals to indicate TRUE_COLOR support. - if color_term == "24bit": - pass - elif color_term == "truecolor": - if term.startswith("screen"): - # tmux supports TRUE_COLOR, screen only ANSI256 - if os.getenv("TERM_PROGRAM") != "tmux": - return ANSI256 - return TRUE_COLOR - elif color_term == "yes": - pass - elif color_term == "true": - return ANSI256 - - # TERM is used by most terminals to indicate color support. - if term == "xterm-kitty" or term == "wezterm" or term == "xterm-ghostty": - return TRUE_COLOR - elif term == "linux": - return ANSI - - if "256color" in term: - return ANSI256 - - if "color" in term: - return ANSI - - if "ansi" in term: - return ANSI - - return ASCII - - -@register_passable -struct Profile: - alias valid = InlineArray[Int, 4](TRUE_COLOR, ANSI256, ANSI, ASCII) - var value: Int - - fn __init__(inout self, value: Int): - """ - Initialize a new profile with the given profile type. - - Args: - value: The setting to use for this profile. Valid values: [TRUE_COLOR, ANSI256, ANSI, ASCII]. - """ - if value not in Self.valid: - self.value = TRUE_COLOR - return - - self.value = value - - fn __init__(inout self): - """ - Initialize a new profile with the given profile type. - """ - self.value = get_color_profile() - - fn __copyinit__(inout self, other: Profile): - self.value = other.value - - fn convert(self, color: AnyColor) -> AnyColor: - """Degrades a color based on the terminal profile. - - Args: - color: The color to convert to the current profile. - """ - if self.value == ASCII: - return NoColor() - - if color.isa[NoColor](): - return color[NoColor] - elif color.isa[ANSIColor](): - return color[ANSIColor] - elif color.isa[ANSI256Color](): - if self.value == ANSI: - return ansi256_to_ansi(color[ANSI256Color].value) - - return color[ANSI256Color] - elif color.isa[RGBColor](): - var h = hex_to_rgb(color[RGBColor].value) - - if self.value != TRUE_COLOR: - var ansi256 = hex_to_ansi256( - hue.Color(h[0].cast[DType.float64](), h[1].cast[DType.float64](), h[2].cast[DType.float64]()) - ) - if self.value == ANSI: - return ansi256_to_ansi(ansi256.value) - - return ansi256 - - return color[RGBColor] - - # If it somehow gets here, just return No Color until I can figure out how to just return whatever color was passed in. - return color[NoColor] - - fn color(self, value: UInt32) -> AnyColor: - """Color creates a Color from a string. Valid inputs are hex colors, as well as - ANSI color codes (0-15, 16-255). If an invalid input is passed in, NoColor() is returned which will not apply any coloring. - - Args: - value: The string to convert to a color. - """ - if self.value == ASCII: - return NoColor() - - if value < 16: - return self.convert(ANSIColor(value)) - elif value < 256: - return self.convert(ANSI256Color(value)) - - return self.convert(RGBColor(value)) diff --git a/external/mist/renderers.mojo b/external/mist/renderers.mojo deleted file mode 100644 index 15c2b02..0000000 --- a/external/mist/renderers.mojo +++ /dev/null @@ -1,116 +0,0 @@ -from .style import Style, new_style -from .profile import Profile - - -alias RED = 0xE88388 -alias GREEN = 0xA8CC8C -alias YELLOW = 0xDBAB79 -alias BLUE = 0x71BEF2 -alias MAGENTA = 0xD290E4 -alias CYAN = 0x66C2CD -alias GRAY = 0xB9BFCA - - -# Convenience functions for quick style application -fn render_as_color(text: String, color: UInt32) -> String: - var profile = Profile() - return new_style(profile.value).foreground(color=profile.color(color)).render(text) - - -fn red(text: String) -> String: - """Apply red color to the text.""" - return render_as_color(text, RED) - - -fn green(text: String) -> String: - """Apply green color to the text.""" - return render_as_color(text, GREEN) - - -fn yellow(text: String) -> String: - """Apply yellow color to the text.""" - return render_as_color(text, YELLOW) - - -fn blue(text: String) -> String: - """Apply blue color to the text.""" - return render_as_color(text, BLUE) - - -fn magenta(text: String) -> String: - """Apply magenta color to the text.""" - return render_as_color(text, MAGENTA) - - -fn cyan(text: String) -> String: - """Apply cyan color to the text.""" - return render_as_color(text, CYAN) - - -fn gray(text: String) -> String: - """Apply gray color to the text.""" - return render_as_color(text, GRAY) - - -fn render_with_background_color(text: String, color: UInt32) -> String: - var profile = Profile() - return new_style().background(color=profile.color(color)).render(text) - - -fn red_background(text: String) -> String: - """Apply red background color to the text.""" - return render_with_background_color(text, RED) - - -fn green_background(text: String) -> String: - """Apply green background color to the text.""" - return render_with_background_color(text, GREEN) - - -fn yellow_background(text: String) -> String: - """Apply yellow background color to the text.""" - return render_with_background_color(text, YELLOW) - - -fn blue_background(text: String) -> String: - """Apply blue background color to the text.""" - return render_with_background_color(text, BLUE) - - -fn magenta_background(text: String) -> String: - """Apply magenta background color to the text.""" - return render_with_background_color(text, MAGENTA) - - -fn cyan_background(text: String) -> String: - """Apply cyan background color to the text.""" - return render_with_background_color(text, CYAN) - - -fn gray_background(text: String) -> String: - """Apply gray background color to the text.""" - return render_with_background_color(text, GRAY) - - -fn bold(text: String) -> String: - return new_style().bold().render(text) - - -fn faint(text: String) -> String: - return new_style().faint().render(text) - - -fn italic(text: String) -> String: - return new_style().italic().render(text) - - -fn underline(text: String) -> String: - return new_style().underline().render(text) - - -fn overline(text: String) -> String: - return new_style().overline().render(text) - - -fn crossout(text: String) -> String: - return new_style().crossout().render(text) diff --git a/external/mist/screen.mojo b/external/mist/screen.mojo deleted file mode 100644 index f10dc67..0000000 --- a/external/mist/screen.mojo +++ /dev/null @@ -1,386 +0,0 @@ -from external.gojo.fmt import sprintf -from .style import bel, csi, reset, osc -from .color import AnyColor, NoColor, ANSIColor, ANSI256Color, RGBColor - - -# Sequence definitions. -## Cursor positioning. -alias cursor_up_seq = "%dA" -alias cursor_down_seq = "%dB" -alias cursor_forward_seq = "%dC" -alias cursor_back_seq = "%dD" -alias cursor_next_line_seq = "%dE" -alias cursor_previous_line_seq = "%dF" -alias cursor_horizontal_seq = "%dG" -alias cursor_position_seq = "%d;%dH" -alias erase_display_seq = "%dJ" -alias erase_line_seq = "%dK" -alias scroll_up_seq = "%dS" -alias scroll_down_seq = "%dT" -alias save_cursor_position_seq = "s" -alias restore_cursor_position_seq = "u" -alias change_scrolling_region_seq = "%d;%dr" -alias insert_line_seq = "%dL" -alias delete_line_seq = "%dM" - -## Explicit values for EraseLineSeq. -alias erase_line_right_seq = "0K" -alias erase_line_left_seq = "1K" -alias erase_entire_line_seq = "2K" - -## Mouse -alias enable_mouse_press_seq = "?9h" # press only (X10) -alias disable_mouse_press_seq = "?9l" -alias enable_mouse_seq = "?1000h" # press, release, wheel -alias disable_mouse_seq = "?1000l" -alias enable_mouse_hilite_seq = "?1001h" # highlight -alias disable_mouse_hilite_seq = "?1001l" -alias enable_mouse_cell_motion_seq = "?1002h" # press, release, move on pressed, wheel -alias disable_mouse_cell_motion_seq = "?1002l" -alias enable_mouse_all_motion_seq = "?1003h" # press, release, move, wheel -alias disable_mouse_all_motion_seq = "?1003l" -alias enable_mouse_extended_mode_seq = "?1006h" # press, release, move, wheel, extended coordinates -alias disable_mouse_extended_mode_seq = "?1006l" -alias enable_mouse_pixels_mode_seq = "?1016h" # press, release, move, wheel, extended pixel coordinates -alias disable_mouse_pixels_mode_seq = "?1016l" - -## Screen -alias restore_screen_seq = "?47l" -alias save_screen_seq = "?47h" -alias alt_screen_seq = "?1049h" -alias exit_alt_screen_seq = "?1049l" - -## Bracketed paste. -## https:#en.wikipedia.org/wiki/Bracketed-paste -alias enable_bracketed_paste_seq = "?2004h" -alias disable_bracketed_paste_seq = "?2004l" -alias start_bracketed_paste_seq = "200~" -alias end_bracketed_paste_seq = "201~" - -## Session -alias set_window_title_seq = "2;%s" + bel -alias set_foreground_color_seq = "10;%s" + bel -alias set_background_color_seq = "11;%s" + bel -alias set_cursor_color_seq = "12;%s" + bel -alias show_cursor_seq = "?25h" -alias hide_cursor_seq = "?25l" - - -fn reset_terminal(): - """Reset the terminal to its default style, removing any active styles.""" - print(csi + reset + "m", end="") - - -fn set_foreground_color(color: AnyColor): - """Sets the default foreground color. - - Args: - color: The color to set. - """ - var c: String = "" - - if color.isa[ANSIColor](): - c = color[ANSIColor].sequence(False) - elif color.isa[ANSI256Color](): - c = color[ANSI256Color].sequence(False) - elif color.isa[RGBColor](): - c = color[RGBColor].sequence(False) - - print(osc + set_foreground_color_seq, c, end="") - - -fn set_background_color(color: AnyColor): - """Sets the default background color. - - Args: - color: The color to set. - """ - var c: String = "" - if color.isa[NoColor](): - pass - elif color.isa[ANSIColor](): - c = color[ANSIColor].sequence(True) - elif color.isa[ANSI256Color](): - c = color[ANSI256Color].sequence(True) - elif color.isa[RGBColor](): - c = color[RGBColor].sequence(True) - - print(osc + set_background_color_seq, c, end="") - - -fn set_cursor_color(color: AnyColor): - """Sets the cursor color. - - Args: - color: The color to set. - """ - var c: String = "" - if color.isa[NoColor](): - pass - elif color.isa[ANSIColor](): - c = color[ANSIColor].sequence(True) - elif color.isa[ANSI256Color](): - c = color[ANSI256Color].sequence(True) - elif color.isa[RGBColor](): - c = color[RGBColor].sequence(True) - - print(osc + set_cursor_color_seq, c, end="") - - -fn restore_screen(): - """Restores a previously saved screen state.""" - print(csi + restore_screen_seq, end="") - - -fn save_screen(): - """Saves the screen state.""" - print(csi + save_screen_seq, end="") - - -fn alt_screen(): - """Switches to the alternate screen buffer. The former view can be restored with ExitAltScreen().""" - print(csi + alt_screen_seq, end="") - - -fn exit_alt_screen(): - """Exits the alternate screen buffer and returns to the former terminal view.""" - print(csi + exit_alt_screen_seq, end="") - - -fn clear_screen(): - """Clears the visible portion of the terminal.""" - print(sprintf(csi + erase_display_seq, UInt16(2)), end="") - move_cursor(1, 1) - - -fn move_cursor(row: UInt16, column: Int): - """Moves the cursor to a given position. - - Args: - row: The row to move to. - column: The column to move to. - """ - print(sprintf(csi + cursor_position_seq, row, column), end="") - - -fn hide_cursor(): - """TODO: Show and Hide cursor don't seem to work ATM. HideCursor hides the cursor.""" - print(csi + hide_cursor_seq, end="") - - -fn show_cursor(): - """Shows the cursor.""" - print(csi + show_cursor_seq, end="") - - -fn save_cursor_position(): - """Saves the cursor position.""" - print(csi + save_cursor_position_seq, end="") - - -fn restore_cursor_position(): - """Restores a saved cursor position.""" - print(csi + restore_cursor_position_seq, end="") - - -fn cursor_up(n: Int): - """Moves the cursor up a given number of lines. - - Args: - n: The number of lines to move up. - """ - print(sprintf(csi + cursor_up_seq, n), end="") - - -fn cursor_down(n: Int): - """Moves the cursor down a given number of lines. - - Args: - n: The number of lines to move down. - """ - print(sprintf(csi + cursor_down_seq, n), end="") - - -fn cursor_forward(n: Int): - """Moves the cursor up a given number of lines. - - Args: - n: The number of lines to move forward. - """ - print(sprintf(csi + cursor_forward_seq, n), end="") - - -fn cursor_back(n: Int): - """Moves the cursor backwards a given number of cells. - - Args: - n: The number of cells to move back. - """ - print(sprintf(csi + cursor_back_seq, n), end="") - - -fn cursor_next_line(n: Int): - """Moves the cursor down a given number of lines and places it at the beginning of the line. - - Args: - n: The number of lines to move down. - """ - print(sprintf(csi + cursor_next_line_seq, n), end="") - - -fn cursor_prev_line(n: Int): - """Moves the cursor up a given number of lines and places it at the beginning of the line. - - Args: - n: The number of lines to move back. - """ - print(sprintf(csi + cursor_previous_line_seq, n), end="") - - -fn clear_line(): - """Clears the current line.""" - print(csi + erase_entire_line_seq, end="") - - -fn clear_line_left(): - """Clears the line to the left of the cursor.""" - print(csi + erase_line_left_seq, end="") - - -fn clear_line_right(): - """Clears the line to the right of the cursor.""" - print(csi + erase_line_right_seq, end="") - - -fn clear_lines(n: Int): - """Clears a given number of lines. - - Args: - n: The number of lines to clear. - """ - var clear_line = sprintf(csi + erase_line_seq, UInt16(2)) - var cursor_up = sprintf(csi + cursor_up_seq, UInt16(1)) - var movement = (cursor_up + clear_line) * n - print(clear_line + movement, end="") - - -fn change_scrolling_region(top: UInt16, bottom: UInt16): - """Sets the scrolling region of the terminal. - - Args: - top: The top of the scrolling region. - bottom: The bottom of the scrolling region. - """ - print(sprintf(csi + change_scrolling_region_seq, top, bottom), end="") - - -fn insert_lines(n: Int): - """Inserts the given number of lines at the top of the scrollable - region, pushing lines below down. - - Args: - n: The number of lines to insert. - """ - print(sprintf(csi + insert_line_seq, n), end="") - - -fn delete_lines(n: Int): - """Deletes the given number of lines, pulling any lines in - the scrollable region below up. - - Args: - n: The number of lines to delete. - """ - print(sprintf(csi + delete_line_seq, n), end="") - - -fn enable_mouse_press(): - """Enables X10 mouse mode. Button press events are sent only.""" - print(csi + enable_mouse_press_seq, end="") - - -fn disable_mouse_press(): - """Disables X10 mouse mode.""" - print(csi + disable_mouse_press_seq, end="") - - -fn enable_mouse(): - """Enables Mouse Tracking mode.""" - print(csi + enable_mouse_seq, end="") - - -fn disable_mouse(): - """Disables Mouse Tracking mode.""" - print(csi + disable_mouse_seq, end="") - - -fn enable_mouse_hilite(): - """Enables Hilite Mouse Tracking mode.""" - print(csi + enable_mouse_hilite_seq, end="") - - -fn disable_mouse_hilite(): - """Disables Hilite Mouse Tracking mode.""" - print(csi + disable_mouse_hilite_seq, end="") - - -fn enable_mouse_cell_motion(): - """Enables Cell Motion Mouse Tracking mode.""" - print(csi + enable_mouse_cell_motion_seq, end="") - - -fn disable_mouse_cell_motion(): - """Disables Cell Motion Mouse Tracking mode.""" - print(csi + disable_mouse_cell_motion_seq, end="") - - -fn enable_mouse_all_motion(): - """Enables All Motion Mouse mode.""" - print(csi + enable_mouse_all_motion_seq, end="") - - -fn disable_mouse_all_motion(): - """Disables All Motion Mouse mode.""" - print(csi + disable_mouse_all_motion_seq, end="") - - -fn enable_mouse_extended_mode(): - """Enables Extended Mouse mode (SGR). This should be - enabled in conjunction with EnableMouseCellMotion, and EnableMouseAllMotion.""" - print(csi + enable_mouse_extended_mode_seq, end="") - - -fn disable_mouse_extended_mode(): - """Disables Extended Mouse mode (SGR).""" - print(csi + disable_mouse_extended_mode_seq, end="") - - -fn enable_mouse_pixels_mode(): - """Enables Pixel Motion Mouse mode (SGR-Pixels). This - should be enabled in conjunction with EnableMouseCellMotion, and - EnableMouseAllMotion.""" - print(csi + enable_mouse_pixels_mode_seq, end="") - - -fn disable_mouse_pixels_mode(): - """Disables Pixel Motion Mouse mode (SGR-Pixels).""" - print(csi + disable_mouse_pixels_mode_seq, end="") - - -fn set_window_title(title: String): - """Sets the terminal window title. - - Args: - title: The title to set. - """ - print(osc + set_window_title_seq, title, end="") - - -fn enable_bracketed_paste(): - """Enables bracketed paste.""" - print(csi + enable_bracketed_paste_seq, end="") - - -fn disable_bracketed_paste(): - """Disables bracketed paste.""" - print(csi + disable_bracketed_paste_seq, end="") diff --git a/external/mist/style.mojo b/external/mist/style.mojo deleted file mode 100644 index 5eb06a3..0000000 --- a/external/mist/style.mojo +++ /dev/null @@ -1,228 +0,0 @@ -from external.gojo.strings import StringBuilder -from .color import ( - Color, - NoColor, - ANSIColor, - ANSI256Color, - RGBColor, - AnyColor, - hex_to_rgb, - hex_to_ansi256, - ansi256_to_ansi, -) -from .profile import get_color_profile, ASCII - -# Text formatting sequences -alias reset = "0" -alias bold = "1" -alias faint = "2" -alias italic = "3" -alias underline = "4" -alias blink = "5" -alias reverse = "7" -alias crossout = "9" -alias overline = "53" - -# ANSI Operations -alias escape = chr(27) # Escape character -alias bel = "\a" # Bell -alias csi = escape + "[" # Control Sequence Introducer -alias osc = escape + "]" # Operating System Command -alias st = escape + chr(92) # String Terminator - Might not work, haven't tried. 92 should be a raw backslash - -# clear terminal and return cursor to top left -alias clear = escape + "[2J" + escape + "[H" - - -@value -struct Style: - """Style stores a list of styles to format text with. These styles are ANSI sequences which modify text (and control the terminal). - In reality, these styles are turning visual terminal features on and off around the text it's styling. - - This struct should be considered immutable and each style added returns a new instance of itself rather than modifying the struct in place. - It's recommended to use `new_style()` function to create a new instance of Style so that you can chain style methods together. - Example: - ```mojo - import mist - - var style = mist.new_style().foreground(0xE88388) - print(style.render("Hello World")) - ``` - """ - - var styles: List[String] - var profile: Profile - - fn __init__(inout self, profile: Profile, *, styles: List[String] = List[String]()): - """Constructs a Style. Use new_style() instead of __init__ to chain function calls. - - Args: - profile: The color profile to use for color conversion. - styles: A list of ANSI styles to apply to the text. - """ - self.styles = styles - self.profile = profile - - fn __init__(inout self, *, styles: List[String] = List[String]()): - """Constructs a Style. Use new_style() instead of __init__ to chain function calls. - - Args: - styles: A list of ANSI styles to apply to the text. - """ - self.styles = styles - self.profile = Profile() - - fn _add_style(self, style: String) -> Self: - """Creates a deepcopy of Self, adds a style to it's list of styles, and returns that. Immutability instead of mutating the object. - - Args: - style: The ANSI style to add to the list of styles. - """ - var new = self - new.styles.append(style) - return new - - fn get_styles(self) -> List[String]: - """Return a deepcopy of the styles list.""" - return List[String](self.styles) - - fn bold(self) -> Self: - """Makes the text bold when rendered.""" - return self._add_style(bold) - - fn faint(self) -> Self: - """Makes the text faint when rendered.""" - return self._add_style(faint) - - fn italic(self) -> Self: - """Makes the text italic when rendered.""" - return self._add_style(italic) - - fn underline(self) -> Self: - """Makes the text underlined when rendered.""" - return self._add_style(underline) - - fn blink(self) -> Self: - """Makes the text blink when rendered.""" - return self._add_style(blink) - - fn reverse(self) -> Self: - """Makes the text have reversed background and foreground colors when rendered.""" - return self._add_style(reverse) - - fn crossout(self) -> Self: - """Makes the text crossed out when rendered.""" - return self._add_style(crossout) - - fn overline(self) -> Self: - """Makes the text overlined when rendered.""" - return self._add_style(overline) - - fn background(self, *, color: AnyColor) -> Self: - """Set the background color of the text when it's rendered. - - Args: - color: The color value to set the background to. This can be a hex value, an ANSI color, or an RGB color. - - Returns: - A new Style with the background color set. - """ - if color.isa[NoColor](): - return Self(self.profile, styles=self.styles) - - var sequence: String = "" - if color.isa[ANSIColor](): - var c = color[ANSIColor] - sequence = c.sequence(True) - elif color.isa[ANSI256Color](): - var c = color[ANSI256Color] - sequence = c.sequence(True) - elif color.isa[RGBColor](): - var c = color[RGBColor] - sequence = c.sequence(True) - return self._add_style(sequence) - - fn background(self, color_value: UInt32) -> Self: - """Shorthand for using the style profile to set the background color of the text. - - Args: - color_value: The color value to set the background to. This can be a hex value, an ANSI color, or an RGB color. - - Returns: - A new Style with the background color set. - """ - return self.background(color=self.profile.color(color_value)) - - fn foreground(self, *, color: AnyColor) -> Self: - """Set the foreground color of the text. - - Args: - color: The color value to set the foreground to. This can be a hex value, an ANSI color, or an RGB color. - - Returns: - A new Style with the foreground color set. - """ - if color.isa[NoColor](): - return Self(self.profile, styles=self.styles) - - var sequence: String = "" - if color.isa[ANSIColor](): - sequence = color[ANSIColor].sequence(False) - elif color.isa[ANSI256Color](): - sequence = color[ANSI256Color].sequence(False) - elif color.isa[RGBColor](): - sequence = color[RGBColor].sequence(False) - return self._add_style(sequence) - - fn foreground(self, color_value: UInt32) -> Self: - """Shorthand for using the style profile to set the foreground color of the text. - - Args: - color_value: The color value to set the foreground to. This can be a hex value, an ANSI color, or an RGB color. - - Returns: - A new Style with the foreground color set. - """ - return self.foreground(color=self.profile.color(color_value)) - - fn render(self, text: String) -> String: - """Renders text with the styles applied to it. - - Args: - text: The text to render with the styles applied. - - Returns: - The text with the styles applied. - """ - if self.profile.value == ASCII: - return text - - if len(self.styles) == 0: - return text - - var builder = StringBuilder() - _ = builder.write_string(csi) - for i in range(len(self.styles)): - _ = builder.write_string(";") - _ = builder.write_string(self.styles[i]) - _ = builder.write_string("m") - _ = builder.write_string(text) - _ = builder.write_string(csi) - _ = builder.write_string(reset) - _ = builder.write_string("m") - - return builder.render() - - -fn new_style(profile: Optional[Int] = None) -> Style: - """Creates a new Style with no styles applied. - - Args: - profile: The color profile to use for color conversion. - - Returns: - A new Style with the given color profile. - """ - if profile: - return Style(profile.value()[]) - return Style() diff --git a/external/weave/__init__.mojo b/external/weave/__init__.mojo deleted file mode 100644 index e4dd26a..0000000 --- a/external/weave/__init__.mojo +++ /dev/null @@ -1,13 +0,0 @@ -from ._dedent import dedent -from ._indent import indent -from ._margin import margin -from ._padding import padding -from ._truncate import truncate, truncate_with_tail -from ._wrap import wrap -from ._wordwrap import wordwrap - - -alias SPACE = String(" ") -alias TAB_BYTE = ord("\t") -alias SPACE_BYTE = ord(" ") -alias NEWLINE_BYTE = ord("\n") diff --git a/external/weave/_dedent.mojo b/external/weave/_dedent.mojo deleted file mode 100644 index 9063146..0000000 --- a/external/weave/_dedent.mojo +++ /dev/null @@ -1,91 +0,0 @@ -from external.gojo.bytes import buffer - - -fn dedent(text: String) -> String: - """Automatically detects the maximum indentation shared by all lines and - trims them accordingly. - - Args: - text: The string to dedent. - - Returns: - The dedented string. - - Example Usage: - ```mojo - from weave import dedent - - fn main() -> None: - var text = dedent(" Hello, World!\\n This is a test.\\n \\n") - print(text) - ``` - . - """ - var indent = min_indent(text.as_bytes_slice()) - if indent == 0: - return text - - return apply_dedent(text.as_bytes_slice(), indent) - - -fn min_indent(bytes: Span[UInt8]) -> Int: - """Detects the indentation level shared by all lines. - - Args: - bytes: The text to dedent as as bytes slice. - - Returns: - The minimum indentation level. - """ - var cur_indent = 0 - var min_indent = 0 - var should_append = True - var i = 0 - - while i < len(bytes): - if bytes[i] == TAB_BYTE or bytes[i] == SPACE_BYTE: - if should_append: - cur_indent += 1 - elif bytes[i] == NEWLINE_BYTE: - cur_indent = 0 - should_append = True - else: - if cur_indent > 0 and (min_indent == 0 or cur_indent < min_indent): - min_indent = cur_indent - cur_indent = 0 - should_append = False - - i += 1 - - return min_indent - - -fn apply_dedent(bytes: Span[UInt8], indent: Int) -> String: - """Dedents a string by removing the shared indentation level. - - Args: - bytes: The text to dedent as as bytes slice. - indent: The number of spaces to remove from the beginning of each line. - - Returns: - A new dedented string. - """ - var omitted: Int = 0 - var buf = buffer.new_buffer() - var i: Int = 0 - - while i < len(bytes): - if bytes[i] == TAB_BYTE or bytes[i] == SPACE_BYTE: - if omitted < indent: - omitted += 1 - else: - _ = buf.write_byte(bytes[i]) - elif bytes[i] == NEWLINE_BYTE: - omitted = 0 - _ = buf.write_byte(bytes[i]) - else: - _ = buf.write_byte(bytes[i]) - - i += 1 - - return str(buf) diff --git a/external/weave/_indent.mojo b/external/weave/_indent.mojo deleted file mode 100644 index 514587a..0000000 --- a/external/weave/_indent.mojo +++ /dev/null @@ -1,143 +0,0 @@ -from external.gojo.bytes import buffer -from external.gojo.unicode import UnicodeString -import .ansi - - -struct Writer(Stringable, Movable): - """A writer that indents content by a given number of spaces. - - Example Usage: - ```mojo - from weave import _indent as indent - - fn main(): - var writer = indent.Writer(4) - _ = writer.write("Hello, World!".as_bytes_slice()) - print(String(writer.as_string_slice())) - ``` - """ - - var indent: UInt8 - """The number of spaces to indent each line.""" - var ansi_writer: ansi.Writer - """The ANSI aware writer that stores the text content.""" - var skip_indent: Bool - """Whether to skip the indentation for the next line.""" - var in_ansi: Bool - """Whether the current character is part of an ANSI escape sequence.""" - - fn __init__(inout self, indent: UInt8): - """Initializes a new indent-writer instance. - - Args: - indent: The number of spaces to indent each line. - """ - self.indent = indent - self.ansi_writer = ansi.Writer() - self.skip_indent = False - self.in_ansi = False - - fn __moveinit__(inout self, owned other: Self): - self.indent = other.indent - self.ansi_writer = other.ansi_writer^ - self.skip_indent = other.skip_indent - self.in_ansi = other.in_ansi - - fn __str__(self) -> String: - return str(self.ansi_writer.forward) - - fn as_bytes(self) -> List[UInt8]: - """Returns the indented result as a byte list.""" - return self.ansi_writer.forward.bytes() - - fn as_bytes_slice(self: Reference[Self]) -> Span[UInt8, self.is_mutable, self.lifetime]: - """Returns the indented result as a byte slice.""" - return self[].ansi_writer.forward.as_bytes_slice() - - fn as_string_slice(self: Reference[Self]) -> StringSlice[self.is_mutable, self.lifetime]: - """Returns the indented result as a string slice.""" - return StringSlice(unsafe_from_utf8=self[].ansi_writer.forward.as_bytes_slice()) - - fn write(inout self, src: Span[UInt8]) -> (Int, Error): - """Writes the given byte slice to the writer. - - Args: - src: The byte slice to write. - - Returns: - The number of bytes written and optional error. - """ - var err = Error() - for rune in UnicodeString(src): - var char = String(rune) - if char == ansi.Marker: - # ANSI escape sequence - self.in_ansi = True - elif self.in_ansi: - if ansi.is_terminator(ord(char)): - # ANSI sequence terminated - self.in_ansi = False - else: - if not self.skip_indent: - self.ansi_writer.reset_ansi() - var bytes_written = 0 - bytes_written, err = self.ansi_writer.write((SPACE * int(self.indent)).as_bytes_slice()) - if err: - return bytes_written, err - - self.skip_indent = True - self.ansi_writer.restore_ansi() - - if char == "\n": - # end of current line - self.skip_indent = False - - var bytes_written = 0 - bytes_written, err = self.ansi_writer.write(char.as_bytes_slice()) - if err: - return bytes_written, err - - return len(src), err - - -fn apply_indent_to_bytes(span: Span[UInt8], indent: UInt8) -> List[UInt8]: - """Shorthand for declaring a new default indent-writer instance, used to immediately indent a byte slice. - Returns a NEW list of bytes. - - Args: - span: The byte slice to indent. - indent: The number of spaces to indent. - - Returns: - A new indented list of bytes. - """ - var writer = Writer(indent) - _ = writer.write(span) - - return writer.as_bytes() - - -fn indent(text: String, indent: UInt8) -> String: - """Shorthand for declaring a new default indent-writer instance, - used to immediately indent a string. - - Args: - text: The string to indent. - indent: The number of spaces to indent. - - Returns: - A new indented string. - - Example Usage: - ```mojo - from weave import indent - - fn main(): - var indented = indent("Hello, World!", 4) - print(indented) - ``` - . - """ - var writer = Writer(indent) - _ = writer.write(text.as_bytes_slice()) - return String(writer.as_string_slice()) diff --git a/external/weave/_margin.mojo b/external/weave/_margin.mojo deleted file mode 100644 index 074c300..0000000 --- a/external/weave/_margin.mojo +++ /dev/null @@ -1,124 +0,0 @@ -from external.gojo.bytes import buffer -import . _padding as padding -import . _indent as indent - - -struct Writer(Stringable, Movable): - """A margin writer that applies a margin to the content. - - Example Usage: - ```mojo - from weave import _margin as margin - - fn main(): - var writer = margin.Writer(5, 2) - _ = writer.write("Hello, World!".as_bytes_slice()) - _ = writer.close() - print(String(writer.as_string_slice())) - ``` - . - """ - - var buf: buffer.Buffer - var pw: padding.Writer - var iw: indent.Writer - - fn __init__(inout self, owned pw: padding.Writer, owned iw: indent.Writer): - """Initializes a new margin-writer instance. - - Args: - pw: The padding-writer instance. - iw: The indent-writer instance. - """ - self.buf = buffer.new_buffer() - self.pw = pw^ - self.iw = iw^ - - fn __init__(inout self, pad: Int, indentation: Int): - """Initializes a new margin-writer instance. - - Args: - pad: Width of the padding of the padding-writer instance. - indentation: Width of the indentation of the padding-writer instance. - """ - self.buf = buffer.new_buffer() - self.pw = padding.Writer(pad) - self.iw = indent.Writer(indentation) - - fn __moveinit__(inout self, owned other: Self): - self.buf = other.buf^ - self.pw = other.pw^ - self.iw = other.iw^ - - fn __str__(self) -> String: - return str(self.buf) - - fn as_bytes(self) -> List[UInt8]: - """Returns the wrapped result as a byte list.""" - return self.buf.bytes() - - fn as_bytes_slice(self: Reference[Self]) -> Span[UInt8, self.is_mutable, self.lifetime]: - """Returns the wrapped result as a byte slice.""" - return self[].buf.as_bytes_slice() - - fn as_string_slice(self: Reference[Self]) -> StringSlice[self.is_mutable, self.lifetime]: - """Returns the wrapped result as a string slice.""" - return StringSlice(unsafe_from_utf8=self[].buf.as_bytes_slice()) - - fn write(inout self, src: Span[UInt8]) -> (Int, Error): - """Writes the given byte slice to the writer. - - Args: - src: The byte slice to write. - - Returns: - The number of bytes written and optional error. - """ - var bytes_written = 0 - var err = Error() - bytes_written, err = self.iw.write(src) - if err: - return bytes_written, err - - return self.pw.write(self.iw.as_bytes_slice()) - - fn close(inout self): - """Will finish the margin operation. Always call it before trying to retrieve the final result.""" - _ = self.pw.close() - _ = self.buf.write(self.pw.as_bytes_slice()) - - -fn apply_margin_to_bytes(span: Span[UInt8], width: UInt8, margin: UInt8) -> List[UInt8]: - """Shorthand for declaring a new default margin-writer instance, - used to immediately apply a margin to a byte slice. - - Args: - span: The byte slice to apply the margin to. - width: The width of the margin. - margin: The margin to apply. - - Returns: - A new margin applied list of bytes. - """ - var writer = Writer(width, margin) - _ = writer.write(span) - _ = writer.close() - return writer.as_bytes() - - -fn margin(text: String, width: UInt8, margin: UInt8) -> String: - """Shorthand for declaring a new default margin-writer instance, - used to immediately apply a margin to a String. - - Args: - text: The byte slice to apply the margin to. - width: The width of the margin. - margin: The margin to apply. - - Returns: - A new margin applied string. - """ - var writer = Writer(width, margin) - _ = writer.write(text.as_bytes_slice()) - _ = writer.close() - return String(writer.as_string_slice()) diff --git a/external/weave/_padding.mojo b/external/weave/_padding.mojo deleted file mode 100644 index b78e705..0000000 --- a/external/weave/_padding.mojo +++ /dev/null @@ -1,167 +0,0 @@ -from external.gojo.bytes import buffer -from external.gojo.unicode import UnicodeString, string_width -import .ansi - - -struct Writer(Stringable, Movable): - """A padding writer that pads content to the given printable cell width. - - Example Usage: - ```mojo - from weave import _padding as padding - - fn main(): - var writer = padding.Writer(4) - _ = writer.write("Hello, World!".as_bytes_slice()) - writer.flush() - print(String(writer.as_string_slice())) - ``` - """ - - var padding: UInt8 - """Padding width to apply to each line.""" - var ansi_writer: ansi.Writer - """The ANSI aware writer that stores intermediary text content.""" - var cache: buffer.Buffer - """The buffer that stores the padded content after it's been flushed.""" - var line_len: Int - """The current line length.""" - var in_ansi: Bool - """Whether the current character is part of an ANSI escape sequence.""" - - fn __init__( - inout self, - padding: UInt8, - line_len: Int = 0, - in_ansi: Bool = False, - ): - """Initializes a new padding-writer instance. - - Args: - padding: The padding width. - line_len: The current line length. - in_ansi: Whether the current character is part of an ANSI escape sequence. - """ - self.padding = padding - self.line_len = line_len - self.in_ansi = in_ansi - self.cache = buffer.new_buffer() - self.ansi_writer = ansi.Writer() - - fn __moveinit__(inout self, owned other: Self): - self.padding = other.padding - self.ansi_writer = other.ansi_writer^ - self.cache = other.cache^ - self.line_len = other.line_len - self.in_ansi = other.in_ansi - - fn __str__(self) -> String: - return str(self.cache) - - fn as_bytes(self) -> List[UInt8]: - """Returns the padded result as a byte list.""" - return self.cache.bytes() - - fn as_bytes_slice(self: Reference[Self]) -> Span[UInt8, self.is_mutable, self.lifetime]: - """Returns the padded result as a byte slice.""" - return self[].cache.as_bytes_slice() - - fn as_string_slice(self: Reference[Self]) -> StringSlice[self.is_mutable, self.lifetime]: - """Returns the padded result as a string slice.""" - return StringSlice(unsafe_from_utf8=self[].cache.as_bytes_slice()) - - fn write(inout self, src: Span[UInt8]) -> (Int, Error): - """Pads content to the given printable cell width. - - Args: - src: The content to write. - - Returns: - The number of bytes written and optional error. - """ - var err = Error() - for rune in UnicodeString(src): - var char = String(rune) - if char == ansi.Marker: - self.in_ansi = True - elif self.in_ansi: - if ansi.is_terminator(ord(char)): - self.in_ansi = False - else: - if char == "\n": - # end of current line, if pad right then add padding before newline - self.pad() - self.ansi_writer.reset_ansi() - self.line_len = 0 - else: - self.line_len += string_width(char) - - var bytes_written = 0 - - bytes_written, err = self.ansi_writer.write(char.as_bytes_slice()) - if err: - return bytes_written, err - - return len(src), err - - fn pad(inout self): - """Pads the current line with spaces to the given width.""" - if self.padding > 0 and UInt8(self.line_len) < self.padding: - var padding = SPACE * (int(self.padding) - self.line_len) - _ = self.ansi_writer.write(padding.as_bytes_slice()) - - fn close(inout self): - """Finishes the padding operation.""" - return self.flush() - - fn flush(inout self): - """Finishes the padding operation. Always call it before trying to retrieve the final result.""" - if self.line_len != 0: - self.pad() - - self.cache.reset() - _ = self.ansi_writer.forward.write_to(self.cache) - self.line_len = 0 - self.in_ansi = False - - -fn apply_padding_to_bytes(bytes: Span[UInt8], width: UInt8) -> List[UInt8]: - """Pads a byte slice to the given printable cell width. - - Args: - bytes: The byte slice to pad. - width: The padding width. - - Returns: - A new padded list of bytes. - """ - var writer = Writer(width) - _ = writer.write(bytes) - _ = writer.flush() - return writer.as_bytes() - - -fn padding(text: String, width: UInt8) -> String: - """Shorthand for declaring a new default padding-writer instance, used to immediately pad a string. - - Args: - text: The string to pad. - width: The padding width. - - Returns: - A new padded string. - - Example Usage: - ```mojo - from weave import padding - - fn main(): - var padded = padding("Hello, World!", 5) - print(padded) - ``` - . - """ - var writer = Writer(width) - _ = writer.write(text.as_bytes_slice()) - _ = writer.flush() - return String(writer.as_string_slice()) diff --git a/external/weave/_truncate.mojo b/external/weave/_truncate.mojo deleted file mode 100644 index 406480e..0000000 --- a/external/weave/_truncate.mojo +++ /dev/null @@ -1,179 +0,0 @@ -from external.gojo.bytes import buffer -from external.gojo.unicode import UnicodeString, rune_width -import .ansi - - -struct Writer(Stringable, Movable): - """A truncating writer that truncates content at the given printable cell width. - - Example Usage: - ```mojo - from weave import _truncate as truncate - - fn main(): - var writer = truncate.Writer(4, tail=".") - _ = writer.write("Hello, World!".as_bytes_slice()) - print(String(writer.as_string_slice())) - ``` - . - """ - - var width: UInt8 - """The maximum printable cell width.""" - var tail: String - """The tail to append to the truncated content.""" - var ansi_writer: ansi.Writer - """The ANSI aware writer that stores the text content.""" - var in_ansi: Bool - """Whether the current character is part of an ANSI escape sequence.""" - - fn __init__(inout self, width: UInt8, tail: String, in_ansi: Bool = False): - """Initializes a new truncate-writer instance. - - Args: - width: The maximum printable cell width. - tail: The tail to append to the truncated content. - in_ansi: Whether the current character is part of an ANSI escape sequence. - """ - self.width = width - self.tail = tail - self.in_ansi = in_ansi - self.ansi_writer = ansi.Writer() - - fn __moveinit__(inout self, owned other: Self): - self.width = other.width - self.tail = other.tail - self.ansi_writer = other.ansi_writer^ - self.in_ansi = other.in_ansi - - fn __str__(self) -> String: - return str(self.ansi_writer.forward) - - fn as_bytes(self) -> List[UInt8]: - """Returns the truncated result as a byte list.""" - return self.ansi_writer.forward.bytes() - - fn as_bytes_slice(self: Reference[Self]) -> Span[UInt8, self.is_mutable, self.lifetime]: - """Returns the truncated result as a byte slice.""" - return self[].ansi_writer.forward.as_bytes_slice() - - fn as_string_slice(self: Reference[Self]) -> StringSlice[self.is_mutable, self.lifetime]: - """Returns the truncated result as a string slice.""" - return StringSlice(unsafe_from_utf8=self[].ansi_writer.forward.as_bytes_slice()) - - fn write(inout self, src: Span[UInt8]) -> (Int, Error): - """Truncates content at the given printable cell width, leaving any ANSI sequences intact. - - Args: - src: The content to write. - - Returns: - The number of bytes written and optional error. - """ - var tw = ansi.printable_rune_width(self.tail) - if self.width < UInt8(tw): - return self.ansi_writer.forward._write(self.tail.as_bytes_slice()) - - self.width -= UInt8(tw) - var cur_width: UInt8 = 0 - - for rune in UnicodeString(src): - var char = String(rune) - if char == ansi.Marker: - # ANSI escape sequence - self.in_ansi = True - elif self.in_ansi: - if ansi.is_terminator(ord(char)): - # ANSI sequence terminated - self.in_ansi = False - else: - cur_width += UInt8(rune_width(ord(char))) - - if cur_width > self.width: - var n = self.ansi_writer.forward.write_string(self.tail) - if self.ansi_writer.last_sequence() != "": - self.ansi_writer.reset_ansi() - return n^ - - _ = self.ansi_writer.write(char.as_bytes_slice()) - - return len(src), Error() - - -fn apply_truncate_to_bytes(span: Span[UInt8], width: UInt8) -> List[UInt8]: - """Truncates a byte slice at the given printable cell width. - - Args: - span: The byte slice to truncate. - width: The maximum printable cell width. - - Returns: - A new truncated byte slice. - """ - return apply_truncate_to_bytes_with_tail(span, width, "") - - -fn apply_truncate_to_bytes_with_tail(span: Span[UInt8], width: UInt8, tail: String) -> List[UInt8]: - """Shorthand for declaring a new default truncate-writer instance, - used to immediately truncate a byte slice. A tail is then added to the end of the byte slice. - - Args: - span: The byte slice to truncate. - width: The maximum printable cell width. - tail: The tail to append to the truncated content. - - Returns: - A new truncated byte slice. - """ - var writer = Writer(width, str(tail)) - _ = writer.write(span) - return writer.as_bytes() - - -fn truncate(text: String, width: UInt8) -> String: - """Shorthand for declaring a new default truncate-writer instance, - used to immediately truncate a String. - - Args: - text: The string to truncate. - width: The maximum printable cell width. - - Returns: - A new truncated string. - - ```mojo - from weave import truncate - - fn main(): - var truncated = truncate("Hello, World!", 5) - print(truncated) - ``` - . - """ - return truncate_with_tail(text, width, "") - - -fn truncate_with_tail(text: String, width: UInt8, tail: String) -> String: - """Shorthand for declaring a new default truncate-writer instance, - used to immediately truncate a String. A tail is then added to the end of the string. - - Args: - text: The string to truncate. - width: The maximum printable cell width. - tail: The tail to append to the truncated content. - - Returns: - A new truncated string. - - ```mojo - from weave import truncate_with_tail - - fn main(): - var truncated = truncate_with_tail("Hello, World!", 5, ".") - print(truncated) - ``` - . - """ - var writer = Writer(width, str(tail)) - _ = writer.write(text.as_bytes_slice()) - return String(writer.as_string_slice()) diff --git a/external/weave/_wordwrap.mojo b/external/weave/_wordwrap.mojo deleted file mode 100644 index b3cd41b..0000000 --- a/external/weave/_wordwrap.mojo +++ /dev/null @@ -1,233 +0,0 @@ -from external.gojo.bytes import buffer -from external.gojo.unicode import UnicodeString -import .ansi - - -alias DEFAULT_NEWLINE = "\n" -alias DEFAULT_TAB_WIDTH = 4 -alias DEFAULT_BREAKPOINT = "-" - - -struct Writer(Stringable, Movable): - """A word-wrapping writer that wraps content based on words at the given limit. - - Example Usage: - ```mojo - from weave import _wordwrap as wordwrap - - fn main(): - var writer = wordwrap.Writer(5) - _ = writer.write("Hello, World!".as_bytes_slice()) - _ = writer.close() - print(String(writer.as_string_slice())) - ``` - . - """ - - var limit: Int - """The maximum number of characters per line.""" - var breakpoint: String - """The character to use as a breakpoint.""" - var newline: String - """The character to use as a newline.""" - var keep_newlines: Bool - """Whether to keep newlines in the content.""" - var buf: buffer.Buffer - """The buffer that stores the word-wrapped content.""" - var space: buffer.Buffer - """The buffer that stores the space between words.""" - var word: buffer.Buffer - """The buffer that stores the current word.""" - var line_len: Int - """The current line length.""" - var ansi: Bool - """Whether the current character is part of an ANSI escape sequence.""" - - fn __init__( - inout self, - limit: Int, - breakpoint: String = DEFAULT_BREAKPOINT, - newline: String = DEFAULT_NEWLINE, - keep_newlines: Bool = True, - line_len: Int = 0, - ansi: Bool = False, - ): - """Initializes a new word-wrap writer instance. - - Args: - limit: The maximum number of characters per line. - breakpoint: The character to use as a breakpoint. - newline: The character to use as a newline. - keep_newlines: Whether to keep newlines in the content. - line_len: The current line length. - ansi: Whether the current character is part of an ANSI escape sequence. - """ - self.limit = limit - self.breakpoint = breakpoint - self.newline = newline - self.keep_newlines = keep_newlines - self.buf = buffer.new_buffer() - self.space = buffer.new_buffer() - self.word = buffer.new_buffer() - self.line_len = line_len - self.ansi = ansi - - fn __moveinit__(inout self, owned other: Self): - self.limit = other.limit - self.breakpoint = other.breakpoint - self.newline = other.newline - self.keep_newlines = other.keep_newlines - self.buf = other.buf^ - self.space = other.space^ - self.word = other.word^ - self.line_len = other.line_len - self.ansi = other.ansi - - fn __str__(self) -> String: - return str(self.buf) - - fn as_bytes(self) -> List[UInt8]: - """Returns the word wrapped result as a byte list.""" - return self.buf.bytes() - - fn as_bytes_slice(self: Reference[Self]) -> Span[UInt8, self.is_mutable, self.lifetime]: - """Returns the word wrapped result as a byte slice.""" - return self[].buf.as_bytes_slice() - - fn as_string_slice(self: Reference[Self]) -> StringSlice[self.is_mutable, self.lifetime]: - """Returns the word wrapped result as a string slice.""" - return StringSlice(unsafe_from_utf8=self[].buf.as_bytes_slice()) - - fn add_space(inout self): - """Write the content of the space buffer to the word-wrap buffer.""" - self.line_len += len(self.space) - _ = self.buf.write(self.space.bytes()) - self.space.reset() - - fn add_word(inout self): - """Write the content of the word buffer to the word-wrap buffer.""" - if len(self.word) > 0: - self.add_space() - self.line_len += ansi.printable_rune_width(str(self.word)) - _ = self.buf.write(self.word.bytes()) - self.word.reset() - - fn add_newline(inout self): - """Write a newline to the word-wrap buffer and reset the line length & space buffer.""" - _ = self.buf.write_byte(NEWLINE_BYTE) - self.line_len = 0 - self.space.reset() - - fn write(inout self, src: Span[UInt8]) -> (Int, Error): - """Write more content to the word-wrap buffer. - - Args: - src: The content to write. - - Returns: - The number of bytes written. and optional error. - """ - if self.limit == 0: - return self.buf._write(src) - - var buf = List[UInt8](src) - buf.append(0) - var s = String(buf^) - if not self.keep_newlines: - s = s.strip() - s = s.replace("\n", " ") - - for rune in UnicodeString(s): - var char = String(rune) - if char == ansi.Marker: - # ANSI escape sequence - _ = self.word._write(char.as_bytes_slice()) - self.ansi = True - elif self.ansi: - _ = self.word._write(char.as_bytes_slice()) - if ansi.is_terminator(ord(char)): - # ANSI sequence terminated - self.ansi = False - elif char == self.newline: - # end of current line - # see if we can add the content of the space buffer to the current line - if len(self.word) == 0: - if self.line_len + len(self.space) > self.limit: - self.line_len = 0 - else: - # preserve whitespace - _ = self.buf._write(self.space.as_bytes_slice()) - - self.space.reset() - - self.add_word() - self.add_newline() - elif char == " ": - # end of current word - self.add_word() - _ = self.space._write(char.as_bytes_slice()) - elif char == self.breakpoint: - # valid breakpoint - self.add_space() - self.add_word() - _ = self.buf._write(char.as_bytes_slice()) - else: - # any other character - _ = self.word._write(char.as_bytes_slice()) - - # add a line break if the current word would exceed the line's - # character limit - if ( - self.line_len + len(self.space) + ansi.printable_rune_width(str(self.word)) > self.limit - and ansi.printable_rune_width(str(self.word)) < self.limit - ): - self.add_newline() - - return len(src), Error() - - fn close(inout self): - """Finishes the word-wrap operation. Always call it before trying to retrieve the final result.""" - self.add_word() - - -fn apply_wordwrap_to_bytes(span: Span[UInt8], limit: Int) -> List[UInt8]: - """Shorthand for declaring a new default WordWrap instance, - used to immediately word-wrap a byte slice. - - Args: - span: The byte slice to word-wrap. - limit: The maximum number of characters per line. - - Returns: - A new word-wrapped byte slice. - """ - var writer = Writer(limit) - _ = writer.write(span) - _ = writer.close() - return writer.as_bytes() - - -fn wordwrap(text: String, limit: Int) -> String: - """Shorthand for declaring a new default WordWrap instance, - used to immediately wrap a string. - - Args: - text: The string to wrap. - limit: The maximum number of characters per line. - - Returns: - A new word-wrapped string. - - ```mojo - from weave import wordwrap - - fn main(): - var wrapped = wordwrap("Hello, World!", 5) - print(wrapped) - ``` - . - """ - var writer = Writer(limit) - _ = writer.write(text.as_bytes_slice()) - _ = writer.close() - return String(writer.as_string_slice()) diff --git a/external/weave/_wrap.mojo b/external/weave/_wrap.mojo deleted file mode 100644 index 2659ed1..0000000 --- a/external/weave/_wrap.mojo +++ /dev/null @@ -1,194 +0,0 @@ -from external.gojo.bytes import buffer -from external.gojo.unicode import UnicodeString, rune_width -import .ansi - -alias DEFAULT_NEWLINE = "\n" -alias DEFAULT_TAB_WIDTH = 4 - - -struct Writer(Stringable, Movable): - """A line-wrapping writer that wraps content based on the given limit. - - Example Usage: - ```mojo - from weave import _wrap as wrap - - fn main(): - var writer = wrap.Writer(5) - _ = writer.write("Hello, World!".as_bytes_slice()) - print(String(writer.as_string_slice())) - ``` - """ - - var limit: Int - """The maximum number of characters per line.""" - var newline: String - """The character to use as a newline.""" - var keep_newlines: Bool - """Whether to keep newlines in the content.""" - var preserve_space: Bool - """Whether to preserve space characters.""" - var tab_width: Int - """The width of a tab character.""" - var buf: buffer.Buffer - """The buffer that stores the wrapped content.""" - var line_len: Int - """The current line length.""" - var ansi: Bool - """Whether the current character is part of an ANSI escape sequence.""" - var forceful_newline: Bool - """Whether to force a newline at the end of the line.""" - - fn __init__( - inout self, - limit: Int, - newline: String = DEFAULT_NEWLINE, - keep_newlines: Bool = True, - preserve_space: Bool = False, - tab_width: Int = DEFAULT_TAB_WIDTH, - line_len: Int = 0, - ansi: Bool = False, - forceful_newline: Bool = False, - ): - """Initializes a new line-wrap writer instance. - - Args: - limit: The maximum number of characters per line. - newline: The character to use as a newline. - keep_newlines: Whether to keep newlines in the content. - preserve_space: Whether to preserve space characters. - tab_width: The width of a tab character. - line_len: The current line length. - ansi: Whether the current character is part of an ANSI escape sequence. - forceful_newline: Whether to force a newline at the end of the line. - """ - self.limit = limit - self.newline = newline - self.keep_newlines = keep_newlines - self.preserve_space = preserve_space - self.tab_width = tab_width - self.buf = buffer.new_buffer() - self.line_len = line_len - self.ansi = ansi - self.forceful_newline = forceful_newline - - fn __moveinit__(inout self, owned other: Self): - self.limit = other.limit - self.newline = other.newline - self.keep_newlines = other.keep_newlines - self.preserve_space = other.preserve_space - self.tab_width = other.tab_width - self.buf = other.buf^ - self.line_len = other.line_len - self.ansi = other.ansi - self.forceful_newline = other.forceful_newline - - fn __str__(self) -> String: - return str(self.buf) - - fn as_bytes(self) -> List[UInt8]: - """Returns the wrapped result as a byte list.""" - return self.buf.bytes() - - fn as_bytes_slice(self: Reference[Self]) -> Span[UInt8, self.is_mutable, self.lifetime]: - """Returns the wrapped result as a byte slice.""" - return self[].buf.as_bytes_slice() - - fn as_string_slice(self: Reference[Self]) -> StringSlice[self.is_mutable, self.lifetime]: - """Returns the wrapped result as a string slice.""" - return StringSlice(unsafe_from_utf8=self[].buf.as_bytes_slice()) - - fn add_newline(inout self): - """Adds a newline to the buffer and resets the line length.""" - _ = self.buf.write_byte(ord(self.newline)) - self.line_len = 0 - - fn write(inout self, src: Span[UInt8]) -> (Int, Error): - """Writes the given byte slice to the buffer, wrapping lines as needed. - - Args: - src: The byte slice to write to the buffer. - - Returns: - The number of bytes written to the buffer and optional error. - """ - var tab_space = SPACE * self.tab_width - var s = String(src) - s = s.replace("\t", tab_space) - if not self.keep_newlines: - s = s.replace("\n", "") - - var width = ansi.printable_rune_width(s) - if self.limit <= 0 or self.line_len + width <= self.limit: - self.line_len += width - return self.buf._write(src) - - for rune in UnicodeString(src): - var char = String(rune) - if char == ansi.Marker: - self.ansi = True - elif self.ansi: - if ansi.is_terminator(ord(char)): - self.ansi = False - elif char == "\n": - self.add_newline() - self.forceful_newline = False - continue - else: - var width = rune_width(ord(char)) - - if self.line_len + width > self.limit: - self.add_newline() - self.forceful_newline = True - - if self.line_len == 0: - if self.forceful_newline and not self.preserve_space and char == " ": - continue - else: - self.forceful_newline = False - - self.line_len += width - _ = self.buf._write(char.as_bytes_slice()) - - return len(src), Error() - - -fn apply_wrap_to_bytes(span: Span[UInt8], limit: Int) -> List[UInt8]: - """Shorthand for declaring a new default Wrap instance, - used to immediately wrap a byte slice. - - Args: - span: The byte slice to wrap. - limit: The maximum line length before wrapping. - - Returns: - A new wrapped byte slice. - """ - var writer = Writer(limit) - _ = writer.write(span) - return writer.as_bytes() - - -fn wrap(text: String, limit: Int) -> String: - """Shorthand for declaring a new default Wrap instance, - used to immediately wrap a string. - - Args: - text: The string to wrap. - limit: The maximum line length before wrapping. - - Returns: - A new wrapped string. - - ```mojo - from weave import wrap - - fn main(): - var wrapped = wrap("Hello, World!", 5) - print(wrapped) - ``` - . - """ - var writer = Writer(limit) - _ = writer.write(text.as_bytes_slice()) - return String(writer.as_string_slice()) diff --git a/external/weave/ansi/__init__.mojo b/external/weave/ansi/__init__.mojo deleted file mode 100644 index 622847a..0000000 --- a/external/weave/ansi/__init__.mojo +++ /dev/null @@ -1,2 +0,0 @@ -from .ansi import printable_rune_width, is_terminator -from .writer import Writer, Marker diff --git a/external/weave/ansi/ansi.mojo b/external/weave/ansi/ansi.mojo deleted file mode 100644 index 6baf555..0000000 --- a/external/weave/ansi/ansi.mojo +++ /dev/null @@ -1,35 +0,0 @@ -from external.gojo.unicode import UnicodeString, rune_width - - -alias Marker = "\x1B" - - -fn is_terminator(c: Int) -> Bool: - return (c >= 0x40 and c <= 0x5A) or (c >= 0x61 and c <= 0x7A) - - -fn printable_rune_width(text: String) -> Int: - """Returns the cell width of the given string. - - Args: - text: String to calculate the width of. - - Returns: - The printable cell width of the string. - """ - var length: Int = 0 - var ansi: Bool = False - - for rune in UnicodeString(text): - var char = ord(rune) - if char == ord(Marker): - # ANSI escape sequence - ansi = True - elif ansi: - if is_terminator(char): - # ANSI sequence terminated - ansi = False - else: - length += rune_width(char) - - return length diff --git a/external/weave/ansi/writer.mojo b/external/weave/ansi/writer.mojo deleted file mode 100644 index 27a4e52..0000000 --- a/external/weave/ansi/writer.mojo +++ /dev/null @@ -1,118 +0,0 @@ -from external.gojo.bytes import buffer -from external.gojo.builtins.bytes import has_suffix -from external.gojo.unicode import UnicodeString -from .ansi import Marker, is_terminator - - -alias ANSI_ESCAPE = String("[0m").as_bytes() -alias ANSI_RESET = String("\x1b[0m").as_bytes() - - -struct Writer: - """A writer that handles ANSI escape sequences in the content. - - Example Usage: - ```mojo - from weave import ansi - - fn main(): - var writer = ansi.Writer() - _ = writer.write("Hello, World!".as_bytes_slice()) - print(str(writer.forward)) - ``` - . - """ - - var forward: buffer.Buffer - """The buffer that stores the text content.""" - var ansi: Bool - """Whether the current character is part of an ANSI escape sequence.""" - var ansi_seq: buffer.Buffer - """The buffer that stores the ANSI escape sequence.""" - var last_seq: buffer.Buffer - """The buffer that stores the last ANSI escape sequence.""" - var seq_changed: Bool - """Whether the ANSI escape sequence has changed.""" - - fn __init__(inout self, owned forward: buffer.Buffer = buffer.new_buffer()): - """Initializes a new ANSI-writer instance. - - Args: - forward: The buffer that stores the text content. - """ - self.forward = forward^ - self.ansi = False - self.ansi_seq = buffer.new_buffer(128) - self.last_seq = buffer.new_buffer(128) - self.seq_changed = False - - fn __moveinit__(inout self, owned other: Writer): - self.forward = other.forward^ - self.ansi = other.ansi - self.ansi_seq = other.ansi_seq^ - self.last_seq = other.last_seq^ - self.seq_changed = other.seq_changed - - fn write(inout self, src: Span[UInt8]) -> (Int, Error): - """Write content to the ANSI buffer. - - Args: - src: The content to write. - - Returns: - The number of bytes written and optional error. - """ - for rune in UnicodeString(src): - var char = String(rune) - if char == Marker: - # ANSI escape sequence - self.ansi = True - self.seq_changed = True - _ = self.ansi_seq._write(char.as_bytes_slice()) - elif self.ansi: - _ = self.ansi_seq._write(char.as_bytes_slice()) - if is_terminator(ord(char)): - self.ansi = False - - if has_suffix(self.ansi_seq.bytes(), ANSI_ESCAPE): - # reset sequence - self.last_seq.reset() - self.seq_changed = False - elif char == "m": - # color code - _ = self.last_seq._write(self.ansi_seq.as_bytes_slice()) - - _ = self.ansi_seq.write_to(self.forward) - else: - _ = self.forward._write(char.as_bytes_slice()) - - return len(src), Error() - - fn write_byte(inout self, byte: UInt8) -> Int: - """Write a byte to the ANSI buffer. - - Args: - byte: The byte to write. - - Returns: - The number of bytes written. - """ - _ = self.forward.write_byte(byte) - return 1 - - fn last_sequence(self) -> String: - """Returns the last ANSI escape sequence.""" - return str(self.last_seq) - - fn reset_ansi(inout self): - """Resets the ANSI escape sequence.""" - if not self.seq_changed: - return - var b = List[UInt8](capacity=512) - for i in range(len(ANSI_RESET)): - b[i] = ANSI_RESET[i] - _ = self.forward.write(b) - - fn restore_ansi(inout self): - """Restores the last ANSI escape sequence.""" - _ = self.forward._write(self.last_seq.as_bytes_slice()) diff --git a/magic.lock b/magic.lock new file mode 100644 index 0000000..28b8698 --- /dev/null +++ b/magic.lock @@ -0,0 +1,1704 @@ +version: 5 +environments: + default: + channels: + - url: https://repo.prefix.dev/mojo-community/ + - url: https://conda.anaconda.org/conda-forge/ + - url: https://conda.modular.com/max/ + packages: + linux-64: + - conda: https://conda.anaconda.org/conda-forge/linux-64/_libgcc_mutex-0.1-conda_forge.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/linux-64/_openmp_mutex-4.5-2_gnu.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/linux-64/bzip2-1.0.8-h4bc722e_7.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/ca-certificates-2024.8.30-hbcca054_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/click-8.1.7-unix_pyh707e725_0.conda + - conda: https://repo.prefix.dev/mojo-community/linux-64/gojo-0.1.9-hb0f4dca_0.conda + - conda: https://repo.prefix.dev/mojo-community/linux-64/hue-0.1.4-hb0f4dca_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/importlib-metadata-8.5.0-pyha770c72_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/importlib_metadata-8.5.0-hd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/jupyter_client-8.6.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/jupyter_core-5.7.2-py312h7900ff3_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/keyutils-1.6.1-h166bdaf_0.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/linux-64/krb5-1.21.3-h659f571_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/ld_impl_linux-64-2.40-hf3520f5_7.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libblas-3.9.0-23_linux64_openblas.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libcblas-3.9.0-23_linux64_openblas.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libedit-3.1.20191231-he28a2e2_2.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/linux-64/libexpat-2.6.3-h5888daf_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libffi-3.4.2-h7f98852_5.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/linux-64/libgcc-14.1.0-h77fa898_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libgcc-ng-14.1.0-h69a702a_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libgfortran-14.1.0-h69a702a_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libgfortran-ng-14.1.0-h69a702a_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libgfortran5-14.1.0-hc5f4f2c_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libgomp-14.1.0-h77fa898_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/liblapack-3.9.0-23_linux64_openblas.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libnsl-2.0.1-hd590300_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libopenblas-0.3.27-pthreads_hac2b453_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libsodium-1.0.20-h4ab18f5_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libsqlite-3.46.1-hadc24fc_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-14.1.0-hc0a3c3a_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-ng-14.1.0-h4852527_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libuuid-2.38.1-h0b41bf4_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libxcrypt-4.4.36-hd590300_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libzlib-1.3.1-h4ab18f5_1.conda + - conda: https://conda.modular.com/max/noarch/max-24.5.0-release.conda + - conda: https://conda.modular.com/max/linux-64/max-core-24.5.0-release.conda + - conda: https://conda.modular.com/max/linux-64/max-python-24.5.0-3.12release.conda + - conda: https://conda.modular.com/max/noarch/mblack-24.5.0-release.conda + - conda: https://repo.prefix.dev/mojo-community/linux-64/mist-0.1.4-hb0f4dca_0.conda + - conda: https://conda.modular.com/max/noarch/mojo-jupyter-24.5.0-release.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/mypy_extensions-1.0.0-pyha770c72_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/ncurses-6.5-he02047a_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/numpy-1.26.4-py312heda63a1_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/openssl-3.3.2-hb9d3cd8_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/packaging-24.1-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pathspec-0.12.1-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/platformdirs-4.3.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/python-3.12.5-h2ad013b_0_cpython.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/python-dateutil-2.9.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/python_abi-3.12-5_cp312.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/pyzmq-26.2.0-py312hbf22597_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/readline-8.2-h8228510_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/six-1.16.0-pyh6c4a22f_0.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/linux-64/tk-8.6.13-noxft_h4845f30_101.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/tornado-6.4.1-py312h66e93f0_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/traitlets-5.14.3-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2024a-h8827d51_1.conda + - conda: https://repo.prefix.dev/mojo-community/linux-64/weave-0.1.1-hb0f4dca_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/xz-5.2.6-h166bdaf_0.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/linux-64/zeromq-4.3.5-ha4adb4c_5.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/zipp-3.20.2-pyhd8ed1ab_0.conda + osx-arm64: + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/bzip2-1.0.8-h99b78c6_7.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/ca-certificates-2024.8.30-hf0a4a13_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/click-8.1.7-unix_pyh707e725_0.conda + - conda: https://repo.prefix.dev/mojo-community/osx-arm64/gojo-0.1.9-h60d57d3_0.conda + - conda: https://repo.prefix.dev/mojo-community/osx-arm64/hue-0.1.4-h60d57d3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/importlib-metadata-8.5.0-pyha770c72_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/importlib_metadata-8.5.0-hd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/jupyter_client-8.6.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/jupyter_core-5.7.2-py312h81bd7bf_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/krb5-1.21.3-h237132a_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libblas-3.9.0-23_osxarm64_openblas.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libcblas-3.9.0-23_osxarm64_openblas.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libcxx-18.1.8-h3ed4263_7.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libedit-3.1.20191231-hc8eb9b7_2.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libexpat-2.6.3-hf9b8971_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libffi-3.4.2-h3422bc3_5.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libgfortran-5.0.0-13_2_0_hd922786_3.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libgfortran5-13.2.0-hf226fd6_3.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/liblapack-3.9.0-23_osxarm64_openblas.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libopenblas-0.3.27-openmp_h517c56d_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libsodium-1.0.20-h99b78c6_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libsqlite-3.46.1-hc14010f_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libzlib-1.3.1-hfb2fe0b_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/llvm-openmp-18.1.8-hde57baf_1.conda + - conda: https://conda.modular.com/max/noarch/max-24.5.0-release.conda + - conda: https://conda.modular.com/max/osx-arm64/max-core-24.5.0-release.conda + - conda: https://conda.modular.com/max/osx-arm64/max-python-24.5.0-3.12release.conda + - conda: https://conda.modular.com/max/noarch/mblack-24.5.0-release.conda + - conda: https://repo.prefix.dev/mojo-community/osx-arm64/mist-0.1.4-h60d57d3_0.conda + - conda: https://conda.modular.com/max/noarch/mojo-jupyter-24.5.0-release.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/mypy_extensions-1.0.0-pyha770c72_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/ncurses-6.5-h7bae524_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/numpy-1.26.4-py312h8442bc7_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/openssl-3.3.2-h8359307_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/packaging-24.1-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pathspec-0.12.1-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/platformdirs-4.3.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/python-3.12.6-h739c21a_0_cpython.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/python-dateutil-2.9.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/python_abi-3.12-5_cp312.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pyzmq-26.2.0-py312hc6335d2_2.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/readline-8.2-h92ec313_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/six-1.16.0-pyh6c4a22f_0.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/tk-8.6.13-h5083fa2_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/tornado-6.4.1-py312h024a12e_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/traitlets-5.14.3-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2024a-h8827d51_1.conda + - conda: https://repo.prefix.dev/mojo-community/osx-arm64/weave-0.1.1-h60d57d3_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/xz-5.2.6-h57fd34a_0.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/zeromq-4.3.5-h64debc3_5.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/zipp-3.20.2-pyhd8ed1ab_0.conda +packages: +- kind: conda + name: _libgcc_mutex + version: '0.1' + build: conda_forge + subdir: linux-64 + url: https://conda.anaconda.org/conda-forge/linux-64/_libgcc_mutex-0.1-conda_forge.tar.bz2 + sha256: fe51de6107f9edc7aa4f786a70f4a883943bc9d39b3bb7307c04c41410990726 + md5: d7c89558ba9fa0495403155b64376d81 + license: None + size: 2562 + timestamp: 1578324546067 +- kind: conda + name: _openmp_mutex + version: '4.5' + build: 2_gnu + build_number: 16 + subdir: linux-64 + url: https://conda.anaconda.org/conda-forge/linux-64/_openmp_mutex-4.5-2_gnu.tar.bz2 + sha256: fbe2c5e56a653bebb982eda4876a9178aedfc2b545f25d0ce9c4c0b508253d22 + md5: 73aaf86a425cc6e73fcf236a5a46396d + depends: + - _libgcc_mutex 0.1 conda_forge + - libgomp >=7.5.0 + constrains: + - openmp_impl 9999 + license: BSD-3-Clause + license_family: BSD + size: 23621 + timestamp: 1650670423406 +- kind: conda + name: bzip2 + version: 1.0.8 + build: h4bc722e_7 + build_number: 7 + subdir: linux-64 + url: https://conda.anaconda.org/conda-forge/linux-64/bzip2-1.0.8-h4bc722e_7.conda + sha256: 5ced96500d945fb286c9c838e54fa759aa04a7129c59800f0846b4335cee770d + md5: 62ee74e96c5ebb0af99386de58cf9553 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc-ng >=12 + license: bzip2-1.0.6 + license_family: BSD + size: 252783 + timestamp: 1720974456583 +- kind: conda + name: bzip2 + version: 1.0.8 + build: h99b78c6_7 + build_number: 7 + subdir: osx-arm64 + url: https://conda.anaconda.org/conda-forge/osx-arm64/bzip2-1.0.8-h99b78c6_7.conda + sha256: adfa71f158cbd872a36394c56c3568e6034aa55c623634b37a4836bd036e6b91 + md5: fc6948412dbbbe9a4c9ddbbcfe0a79ab + depends: + - __osx >=11.0 + license: bzip2-1.0.6 + license_family: BSD + size: 122909 + timestamp: 1720974522888 +- kind: conda + name: ca-certificates + version: 2024.8.30 + build: hbcca054_0 + subdir: linux-64 + url: https://conda.anaconda.org/conda-forge/linux-64/ca-certificates-2024.8.30-hbcca054_0.conda + sha256: afee721baa6d988e27fef1832f68d6f32ac8cc99cdf6015732224c2841a09cea + md5: c27d1c142233b5bc9ca570c6e2e0c244 + license: ISC + size: 159003 + timestamp: 1725018903918 +- kind: conda + name: ca-certificates + version: 2024.8.30 + build: hf0a4a13_0 + subdir: osx-arm64 + url: https://conda.anaconda.org/conda-forge/osx-arm64/ca-certificates-2024.8.30-hf0a4a13_0.conda + sha256: 2db1733f4b644575dbbdd7994a8f338e6ef937f5ebdb74acd557e9dda0211709 + md5: 40dec13fd8348dbe303e57be74bd3d35 + license: ISC + size: 158482 + timestamp: 1725019034582 +- kind: conda + name: click + version: 8.1.7 + build: unix_pyh707e725_0 + subdir: noarch + noarch: python + url: https://conda.anaconda.org/conda-forge/noarch/click-8.1.7-unix_pyh707e725_0.conda + sha256: f0016cbab6ac4138a429e28dbcb904a90305b34b3fe41a9b89d697c90401caec + md5: f3ad426304898027fc619827ff428eca + depends: + - __unix + - python >=3.8 + license: BSD-3-Clause + license_family: BSD + size: 84437 + timestamp: 1692311973840 +- kind: conda + name: gojo + version: 0.1.9 + build: h60d57d3_0 + subdir: osx-arm64 + url: https://repo.prefix.dev/mojo-community/osx-arm64/gojo-0.1.9-h60d57d3_0.conda + sha256: 4c268d0d8d5f1b78a547e78a3db9e8037143918cd1d696f5adb5db55942cef5e + depends: + - max >=24.5.0,<24.6.0 + arch: arm64 + platform: osx + license: MIT + size: 1009999 + timestamp: 1726268309700 +- kind: conda + name: gojo + version: 0.1.9 + build: hb0f4dca_0 + subdir: linux-64 + url: https://repo.prefix.dev/mojo-community/linux-64/gojo-0.1.9-hb0f4dca_0.conda + sha256: 9a49e21b4269368a6d906769bd041b8b91b99da3375d7944f7d8ddd73392c2f0 + depends: + - max >=24.5.0,<24.6.0 + arch: x86_64 + platform: linux + license: MIT + size: 1011206 + timestamp: 1726268249824 +- kind: conda + name: hue + version: 0.1.4 + build: h60d57d3_0 + subdir: osx-arm64 + url: https://repo.prefix.dev/mojo-community/osx-arm64/hue-0.1.4-h60d57d3_0.conda + sha256: efc1be67a3e964d956592718182d2a29c43faffd8cc06a7dcdad9498858c7ef9 + depends: + - max >=24.5.0,<25 + arch: arm64 + platform: osx + license: MIT + size: 484185 + timestamp: 1726264925685 +- kind: conda + name: hue + version: 0.1.4 + build: hb0f4dca_0 + subdir: linux-64 + url: https://repo.prefix.dev/mojo-community/linux-64/hue-0.1.4-hb0f4dca_0.conda + sha256: 3ee8991a3c6f3f4fb579c443752d69fbd0f8091de81c2dec8abfac87c1bc09fc + depends: + - max >=24.5.0,<25 + arch: x86_64 + platform: linux + license: MIT + size: 484109 + timestamp: 1726264922499 +- kind: conda + name: importlib-metadata + version: 8.5.0 + build: pyha770c72_0 + subdir: noarch + noarch: python + url: https://conda.anaconda.org/conda-forge/noarch/importlib-metadata-8.5.0-pyha770c72_0.conda + sha256: 7194700ce1a5ad2621fd68e894dd8c1ceaff9a38723e6e0e5298fdef13017b1c + md5: 54198435fce4d64d8a89af22573012a8 + depends: + - python >=3.8 + - zipp >=0.5 + license: Apache-2.0 + license_family: APACHE + size: 28646 + timestamp: 1726082927916 +- kind: conda + name: importlib_metadata + version: 8.5.0 + build: hd8ed1ab_0 + subdir: noarch + noarch: generic + url: https://conda.anaconda.org/conda-forge/noarch/importlib_metadata-8.5.0-hd8ed1ab_0.conda + sha256: 313b8a05211bacd6b15ab2621cb73d7f41ea5c6cae98db53367d47833f03fef1 + md5: 2a92e152208121afadf85a5e1f3a5f4d + depends: + - importlib-metadata >=8.5.0,<8.5.1.0a0 + license: Apache-2.0 + license_family: APACHE + size: 9385 + timestamp: 1726082930346 +- kind: conda + name: jupyter_client + version: 8.6.2 + build: pyhd8ed1ab_0 + subdir: noarch + noarch: python + url: https://conda.anaconda.org/conda-forge/noarch/jupyter_client-8.6.2-pyhd8ed1ab_0.conda + sha256: 634f065cdd1d0aacd4bb6848ebf240dcebc8578135d65f4ad4aa42b2276c4e0c + md5: 3cdbb2fa84490e5fd44c9f9806c0d292 + depends: + - importlib_metadata >=4.8.3 + - jupyter_core >=4.12,!=5.0.* + - python >=3.8 + - python-dateutil >=2.8.2 + - pyzmq >=23.0 + - tornado >=6.2 + - traitlets >=5.3 + license: BSD-3-Clause + license_family: BSD + size: 106248 + timestamp: 1716472312833 +- kind: conda + name: jupyter_core + version: 5.7.2 + build: py312h7900ff3_0 + subdir: linux-64 + url: https://conda.anaconda.org/conda-forge/linux-64/jupyter_core-5.7.2-py312h7900ff3_0.conda + sha256: 22a6259c2b139191c76ed7633d1865757b3c15007989f6c74304a80f28e5a262 + md5: eee5a2e3465220ed87196bbb5665f420 + depends: + - platformdirs >=2.5 + - python >=3.12,<3.13.0a0 + - python_abi 3.12.* *_cp312 + - traitlets >=5.3 + license: BSD-3-Clause + license_family: BSD + size: 92843 + timestamp: 1710257533875 +- kind: conda + name: jupyter_core + version: 5.7.2 + build: py312h81bd7bf_0 + subdir: osx-arm64 + url: https://conda.anaconda.org/conda-forge/osx-arm64/jupyter_core-5.7.2-py312h81bd7bf_0.conda + sha256: 5ab0e75a30915d34ae27b4a76f1241c2f4cc4419b6b1c838cc1160b9ec8bfaf5 + md5: 209b9cb7159212afce5e16d7a3ee3b47 + depends: + - platformdirs >=2.5 + - python >=3.12,<3.13.0a0 + - python >=3.12,<3.13.0a0 *_cpython + - python_abi 3.12.* *_cp312 + - traitlets >=5.3 + license: BSD-3-Clause + license_family: BSD + size: 93829 + timestamp: 1710257916303 +- kind: conda + name: keyutils + version: 1.6.1 + build: h166bdaf_0 + subdir: linux-64 + url: https://conda.anaconda.org/conda-forge/linux-64/keyutils-1.6.1-h166bdaf_0.tar.bz2 + sha256: 150c05a6e538610ca7c43beb3a40d65c90537497a4f6a5f4d15ec0451b6f5ebb + md5: 30186d27e2c9fa62b45fb1476b7200e3 + depends: + - libgcc-ng >=10.3.0 + license: LGPL-2.1-or-later + size: 117831 + timestamp: 1646151697040 +- kind: conda + name: krb5 + version: 1.21.3 + build: h237132a_0 + subdir: osx-arm64 + url: https://conda.anaconda.org/conda-forge/osx-arm64/krb5-1.21.3-h237132a_0.conda + sha256: 4442f957c3c77d69d9da3521268cad5d54c9033f1a73f99cde0a3658937b159b + md5: c6dc8a0fdec13a0565936655c33069a1 + depends: + - __osx >=11.0 + - libcxx >=16 + - libedit >=3.1.20191231,<3.2.0a0 + - libedit >=3.1.20191231,<4.0a0 + - openssl >=3.3.1,<4.0a0 + license: MIT + license_family: MIT + size: 1155530 + timestamp: 1719463474401 +- kind: conda + name: krb5 + version: 1.21.3 + build: h659f571_0 + subdir: linux-64 + url: https://conda.anaconda.org/conda-forge/linux-64/krb5-1.21.3-h659f571_0.conda + sha256: 99df692f7a8a5c27cd14b5fb1374ee55e756631b9c3d659ed3ee60830249b238 + md5: 3f43953b7d3fb3aaa1d0d0723d91e368 + depends: + - keyutils >=1.6.1,<2.0a0 + - libedit >=3.1.20191231,<3.2.0a0 + - libedit >=3.1.20191231,<4.0a0 + - libgcc-ng >=12 + - libstdcxx-ng >=12 + - openssl >=3.3.1,<4.0a0 + license: MIT + license_family: MIT + size: 1370023 + timestamp: 1719463201255 +- kind: conda + name: ld_impl_linux-64 + version: '2.40' + build: hf3520f5_7 + build_number: 7 + subdir: linux-64 + url: https://conda.anaconda.org/conda-forge/linux-64/ld_impl_linux-64-2.40-hf3520f5_7.conda + sha256: 764b6950aceaaad0c67ef925417594dd14cd2e22fff864aeef455ac259263d15 + md5: b80f2f396ca2c28b8c14c437a4ed1e74 + constrains: + - binutils_impl_linux-64 2.40 + license: GPL-3.0-only + license_family: GPL + size: 707602 + timestamp: 1718625640445 +- kind: conda + name: libblas + version: 3.9.0 + build: 23_linux64_openblas + build_number: 23 + subdir: linux-64 + url: https://conda.anaconda.org/conda-forge/linux-64/libblas-3.9.0-23_linux64_openblas.conda + sha256: edb1cee5da3ac4936940052dcab6969673ba3874564f90f5110f8c11eed789c2 + md5: 96c8450a40aa2b9733073a9460de972c + depends: + - libopenblas >=0.3.27,<0.3.28.0a0 + - libopenblas >=0.3.27,<1.0a0 + constrains: + - liblapacke 3.9.0 23_linux64_openblas + - libcblas 3.9.0 23_linux64_openblas + - liblapack 3.9.0 23_linux64_openblas + - blas * openblas + license: BSD-3-Clause + license_family: BSD + size: 14880 + timestamp: 1721688759937 +- kind: conda + name: libblas + version: 3.9.0 + build: 23_osxarm64_openblas + build_number: 23 + subdir: osx-arm64 + url: https://conda.anaconda.org/conda-forge/osx-arm64/libblas-3.9.0-23_osxarm64_openblas.conda + sha256: 1c30da861e306a25fac8cd30ce0c1b31c9238d04e7768c381cf4d431b4361e6c + md5: acae9191e8772f5aff48ab5232d4d2a3 + depends: + - libopenblas >=0.3.27,<0.3.28.0a0 + - libopenblas >=0.3.27,<1.0a0 + constrains: + - liblapack 3.9.0 23_osxarm64_openblas + - blas * openblas + - liblapacke 3.9.0 23_osxarm64_openblas + - libcblas 3.9.0 23_osxarm64_openblas + license: BSD-3-Clause + license_family: BSD + size: 15103 + timestamp: 1721688997980 +- kind: conda + name: libcblas + version: 3.9.0 + build: 23_linux64_openblas + build_number: 23 + subdir: linux-64 + url: https://conda.anaconda.org/conda-forge/linux-64/libcblas-3.9.0-23_linux64_openblas.conda + sha256: 3e7a3236e7e03e308e1667d91d0aa70edd0cba96b4b5563ef4adde088e0881a5 + md5: eede29b40efa878cbe5bdcb767e97310 + depends: + - libblas 3.9.0 23_linux64_openblas + constrains: + - liblapacke 3.9.0 23_linux64_openblas + - liblapack 3.9.0 23_linux64_openblas + - blas * openblas + license: BSD-3-Clause + license_family: BSD + size: 14798 + timestamp: 1721688767584 +- kind: conda + name: libcblas + version: 3.9.0 + build: 23_osxarm64_openblas + build_number: 23 + subdir: osx-arm64 + url: https://conda.anaconda.org/conda-forge/osx-arm64/libcblas-3.9.0-23_osxarm64_openblas.conda + sha256: c39d944909d0608bd0333398be5e0051045c9451bfd6cc6320732d33375569c8 + md5: bad6ee9b7d5584efc2bc5266137b5f0d + depends: + - libblas 3.9.0 23_osxarm64_openblas + constrains: + - liblapack 3.9.0 23_osxarm64_openblas + - liblapacke 3.9.0 23_osxarm64_openblas + - blas * openblas + license: BSD-3-Clause + license_family: BSD + size: 14991 + timestamp: 1721689017803 +- kind: conda + name: libcxx + version: 18.1.8 + build: h3ed4263_7 + build_number: 7 + subdir: osx-arm64 + url: https://conda.anaconda.org/conda-forge/osx-arm64/libcxx-18.1.8-h3ed4263_7.conda + sha256: 15b4abaa249f0965ce42aeb4a1a2b1b5df9a1f402e7c5bd8156272fd6cad2878 + md5: e0e7d9a2ec0f9509ffdfd5f48da522fb + depends: + - __osx >=11.0 + license: Apache-2.0 WITH LLVM-exception + license_family: Apache + size: 436921 + timestamp: 1725403628507 +- kind: conda + name: libedit + version: 3.1.20191231 + build: hc8eb9b7_2 + build_number: 2 + subdir: osx-arm64 + url: https://conda.anaconda.org/conda-forge/osx-arm64/libedit-3.1.20191231-hc8eb9b7_2.tar.bz2 + sha256: 3912636197933ecfe4692634119e8644904b41a58f30cad9d1fc02f6ba4d9fca + md5: 30e4362988a2623e9eb34337b83e01f9 + depends: + - ncurses >=6.2,<7.0.0a0 + license: BSD-2-Clause + license_family: BSD + size: 96607 + timestamp: 1597616630749 +- kind: conda + name: libedit + version: 3.1.20191231 + build: he28a2e2_2 + build_number: 2 + subdir: linux-64 + url: https://conda.anaconda.org/conda-forge/linux-64/libedit-3.1.20191231-he28a2e2_2.tar.bz2 + sha256: a57d37c236d8f7c886e01656f4949d9dcca131d2a0728609c6f7fa338b65f1cf + md5: 4d331e44109e3f0e19b4cb8f9b82f3e1 + depends: + - libgcc-ng >=7.5.0 + - ncurses >=6.2,<7.0.0a0 + license: BSD-2-Clause + license_family: BSD + size: 123878 + timestamp: 1597616541093 +- kind: conda + name: libexpat + version: 2.6.3 + build: h5888daf_0 + subdir: linux-64 + url: https://conda.anaconda.org/conda-forge/linux-64/libexpat-2.6.3-h5888daf_0.conda + sha256: 4bb47bb2cd09898737a5211e2992d63c555d63715a07ba56eae0aff31fb89c22 + md5: 59f4c43bb1b5ef1c71946ff2cbf59524 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=13 + constrains: + - expat 2.6.3.* + license: MIT + license_family: MIT + size: 73616 + timestamp: 1725568742634 +- kind: conda + name: libexpat + version: 2.6.3 + build: hf9b8971_0 + subdir: osx-arm64 + url: https://conda.anaconda.org/conda-forge/osx-arm64/libexpat-2.6.3-hf9b8971_0.conda + sha256: 5cbe5a199fba14ade55457a468ce663aac0b54832c39aa54470b3889b4c75c4a + md5: 5f22f07c2ab2dea8c66fe9585a062c96 + depends: + - __osx >=11.0 + constrains: + - expat 2.6.3.* + license: MIT + license_family: MIT + size: 63895 + timestamp: 1725568783033 +- kind: conda + name: libffi + version: 3.4.2 + build: h3422bc3_5 + build_number: 5 + subdir: osx-arm64 + url: https://conda.anaconda.org/conda-forge/osx-arm64/libffi-3.4.2-h3422bc3_5.tar.bz2 + sha256: 41b3d13efb775e340e4dba549ab5c029611ea6918703096b2eaa9c015c0750ca + md5: 086914b672be056eb70fd4285b6783b6 + license: MIT + license_family: MIT + size: 39020 + timestamp: 1636488587153 +- kind: conda + name: libffi + version: 3.4.2 + build: h7f98852_5 + build_number: 5 + subdir: linux-64 + url: https://conda.anaconda.org/conda-forge/linux-64/libffi-3.4.2-h7f98852_5.tar.bz2 + sha256: ab6e9856c21709b7b517e940ae7028ae0737546122f83c2aa5d692860c3b149e + md5: d645c6d2ac96843a2bfaccd2d62b3ac3 + depends: + - libgcc-ng >=9.4.0 + license: MIT + license_family: MIT + size: 58292 + timestamp: 1636488182923 +- kind: conda + name: libgcc + version: 14.1.0 + build: h77fa898_1 + build_number: 1 + subdir: linux-64 + url: https://conda.anaconda.org/conda-forge/linux-64/libgcc-14.1.0-h77fa898_1.conda + sha256: 10fa74b69266a2be7b96db881e18fa62cfa03082b65231e8d652e897c4b335a3 + md5: 002ef4463dd1e2b44a94a4ace468f5d2 + depends: + - _libgcc_mutex 0.1 conda_forge + - _openmp_mutex >=4.5 + constrains: + - libgomp 14.1.0 h77fa898_1 + - libgcc-ng ==14.1.0=*_1 + license: GPL-3.0-only WITH GCC-exception-3.1 + license_family: GPL + size: 846380 + timestamp: 1724801836552 +- kind: conda + name: libgcc-ng + version: 14.1.0 + build: h69a702a_1 + build_number: 1 + subdir: linux-64 + url: https://conda.anaconda.org/conda-forge/linux-64/libgcc-ng-14.1.0-h69a702a_1.conda + sha256: b91f7021e14c3d5c840fbf0dc75370d6e1f7c7ff4482220940eaafb9c64613b7 + md5: 1efc0ad219877a73ef977af7dbb51f17 + depends: + - libgcc 14.1.0 h77fa898_1 + license: GPL-3.0-only WITH GCC-exception-3.1 + license_family: GPL + size: 52170 + timestamp: 1724801842101 +- kind: conda + name: libgfortran + version: 5.0.0 + build: 13_2_0_hd922786_3 + build_number: 3 + subdir: osx-arm64 + url: https://conda.anaconda.org/conda-forge/osx-arm64/libgfortran-5.0.0-13_2_0_hd922786_3.conda + sha256: 44e541b4821c96b28b27fef5630883a60ce4fee91fd9c79f25a199f8f73f337b + md5: 4a55d9e169114b2b90d3ec4604cd7bbf + depends: + - libgfortran5 13.2.0 hf226fd6_3 + license: GPL-3.0-only WITH GCC-exception-3.1 + license_family: GPL + size: 110233 + timestamp: 1707330749033 +- kind: conda + name: libgfortran + version: 14.1.0 + build: h69a702a_1 + build_number: 1 + subdir: linux-64 + url: https://conda.anaconda.org/conda-forge/linux-64/libgfortran-14.1.0-h69a702a_1.conda + sha256: ed77f04f873e43a26e24d443dd090631eedc7d0ace3141baaefd96a123e47535 + md5: 591e631bc1ae62c64f2ab4f66178c097 + depends: + - libgfortran5 14.1.0 hc5f4f2c_1 + constrains: + - libgfortran-ng ==14.1.0=*_1 + license: GPL-3.0-only WITH GCC-exception-3.1 + license_family: GPL + size: 52142 + timestamp: 1724801872472 +- kind: conda + name: libgfortran-ng + version: 14.1.0 + build: h69a702a_1 + build_number: 1 + subdir: linux-64 + url: https://conda.anaconda.org/conda-forge/linux-64/libgfortran-ng-14.1.0-h69a702a_1.conda + sha256: a2dc35cb7f87bb5beebf102d4085574c6a740e1df58e743185d4434cc5e4e0ae + md5: 16cec94c5992d7f42ae3f9fa8b25df8d + depends: + - libgfortran 14.1.0 h69a702a_1 + license: GPL-3.0-only WITH GCC-exception-3.1 + license_family: GPL + size: 52212 + timestamp: 1724802086021 +- kind: conda + name: libgfortran5 + version: 13.2.0 + build: hf226fd6_3 + build_number: 3 + subdir: osx-arm64 + url: https://conda.anaconda.org/conda-forge/osx-arm64/libgfortran5-13.2.0-hf226fd6_3.conda + sha256: bafc679eedb468a86aa4636061c55966186399ee0a04b605920d208d97ac579a + md5: 66ac81d54e95c534ae488726c1f698ea + depends: + - llvm-openmp >=8.0.0 + constrains: + - libgfortran 5.0.0 13_2_0_*_3 + license: GPL-3.0-only WITH GCC-exception-3.1 + license_family: GPL + size: 997381 + timestamp: 1707330687590 +- kind: conda + name: libgfortran5 + version: 14.1.0 + build: hc5f4f2c_1 + build_number: 1 + subdir: linux-64 + url: https://conda.anaconda.org/conda-forge/linux-64/libgfortran5-14.1.0-hc5f4f2c_1.conda + sha256: c40d7db760296bf9c776de12597d2f379f30e890b9ae70c1de962ff2aa1999f6 + md5: 10a0cef64b784d6ab6da50ebca4e984d + depends: + - libgcc >=14.1.0 + constrains: + - libgfortran 14.1.0 + license: GPL-3.0-only WITH GCC-exception-3.1 + license_family: GPL + size: 1459939 + timestamp: 1724801851300 +- kind: conda + name: libgomp + version: 14.1.0 + build: h77fa898_1 + build_number: 1 + subdir: linux-64 + url: https://conda.anaconda.org/conda-forge/linux-64/libgomp-14.1.0-h77fa898_1.conda + sha256: c96724c8ae4ee61af7674c5d9e5a3fbcf6cd887a40ad5a52c99aa36f1d4f9680 + md5: 23c255b008c4f2ae008f81edcabaca89 + depends: + - _libgcc_mutex 0.1 conda_forge + license: GPL-3.0-only WITH GCC-exception-3.1 + license_family: GPL + size: 460218 + timestamp: 1724801743478 +- kind: conda + name: liblapack + version: 3.9.0 + build: 23_linux64_openblas + build_number: 23 + subdir: linux-64 + url: https://conda.anaconda.org/conda-forge/linux-64/liblapack-3.9.0-23_linux64_openblas.conda + sha256: 25c7aef86c8a1d9db0e8ee61aa7462ba3b46b482027a65d66eb83e3e6f949043 + md5: 2af0879961951987e464722fd00ec1e0 + depends: + - libblas 3.9.0 23_linux64_openblas + constrains: + - liblapacke 3.9.0 23_linux64_openblas + - libcblas 3.9.0 23_linux64_openblas + - blas * openblas + license: BSD-3-Clause + license_family: BSD + size: 14823 + timestamp: 1721688775172 +- kind: conda + name: liblapack + version: 3.9.0 + build: 23_osxarm64_openblas + build_number: 23 + subdir: osx-arm64 + url: https://conda.anaconda.org/conda-forge/osx-arm64/liblapack-3.9.0-23_osxarm64_openblas.conda + sha256: 13799a137ffc80786725e7e2820d37d4c0d59dbb76013a14c21771415b0a4263 + md5: 754ef44f72ab80fd14eaa789ac393a27 + depends: + - libblas 3.9.0 23_osxarm64_openblas + constrains: + - blas * openblas + - liblapacke 3.9.0 23_osxarm64_openblas + - libcblas 3.9.0 23_osxarm64_openblas + license: BSD-3-Clause + license_family: BSD + size: 14999 + timestamp: 1721689026268 +- kind: conda + name: libnsl + version: 2.0.1 + build: hd590300_0 + subdir: linux-64 + url: https://conda.anaconda.org/conda-forge/linux-64/libnsl-2.0.1-hd590300_0.conda + sha256: 26d77a3bb4dceeedc2a41bd688564fe71bf2d149fdcf117049970bc02ff1add6 + md5: 30fd6e37fe21f86f4bd26d6ee73eeec7 + depends: + - libgcc-ng >=12 + license: LGPL-2.1-only + license_family: GPL + size: 33408 + timestamp: 1697359010159 +- kind: conda + name: libopenblas + version: 0.3.27 + build: openmp_h517c56d_1 + build_number: 1 + subdir: osx-arm64 + url: https://conda.anaconda.org/conda-forge/osx-arm64/libopenblas-0.3.27-openmp_h517c56d_1.conda + sha256: 46cfcc592b5255262f567cd098be3c61da6bca6c24d640e878dc8342b0f6d069 + md5: 71b8a34d70aa567a990162f327e81505 + depends: + - __osx >=11.0 + - libgfortran 5.* + - libgfortran5 >=12.3.0 + - llvm-openmp >=16.0.6 + constrains: + - openblas >=0.3.27,<0.3.28.0a0 + license: BSD-3-Clause + license_family: BSD + size: 2925328 + timestamp: 1720425811743 +- kind: conda + name: libopenblas + version: 0.3.27 + build: pthreads_hac2b453_1 + build_number: 1 + subdir: linux-64 + url: https://conda.anaconda.org/conda-forge/linux-64/libopenblas-0.3.27-pthreads_hac2b453_1.conda + sha256: 714cb82d7c4620ea2635a92d3df263ab841676c9b183d0c01992767bb2451c39 + md5: ae05ece66d3924ac3d48b4aa3fa96cec + depends: + - libgcc-ng >=12 + - libgfortran-ng + - libgfortran5 >=12.3.0 + constrains: + - openblas >=0.3.27,<0.3.28.0a0 + license: BSD-3-Clause + license_family: BSD + size: 5563053 + timestamp: 1720426334043 +- kind: conda + name: libsodium + version: 1.0.20 + build: h4ab18f5_0 + subdir: linux-64 + url: https://conda.anaconda.org/conda-forge/linux-64/libsodium-1.0.20-h4ab18f5_0.conda + sha256: 0105bd108f19ea8e6a78d2d994a6d4a8db16d19a41212070d2d1d48a63c34161 + md5: a587892d3c13b6621a6091be690dbca2 + depends: + - libgcc-ng >=12 + license: ISC + size: 205978 + timestamp: 1716828628198 +- kind: conda + name: libsodium + version: 1.0.20 + build: h99b78c6_0 + subdir: osx-arm64 + url: https://conda.anaconda.org/conda-forge/osx-arm64/libsodium-1.0.20-h99b78c6_0.conda + sha256: fade8223e1e1004367d7101dd17261003b60aa576df6d7802191f8972f7470b1 + md5: a7ce36e284c5faaf93c220dfc39e3abd + depends: + - __osx >=11.0 + license: ISC + size: 164972 + timestamp: 1716828607917 +- kind: conda + name: libsqlite + version: 3.46.1 + build: hadc24fc_0 + subdir: linux-64 + url: https://conda.anaconda.org/conda-forge/linux-64/libsqlite-3.46.1-hadc24fc_0.conda + sha256: 9851c049abafed3ee329d6c7c2033407e2fc269d33a75c071110ab52300002b0 + md5: 36f79405ab16bf271edb55b213836dac + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=13 + - libzlib >=1.3.1,<2.0a0 + license: Unlicense + size: 865214 + timestamp: 1725353659783 +- kind: conda + name: libsqlite + version: 3.46.1 + build: hc14010f_0 + subdir: osx-arm64 + url: https://conda.anaconda.org/conda-forge/osx-arm64/libsqlite-3.46.1-hc14010f_0.conda + sha256: 3725f962f490c5d44dae326d5f5b2e3c97f71a6322d914ccc85b5ddc2e50d120 + md5: 58050ec1724e58668d0126a1615553fa + depends: + - __osx >=11.0 + - libzlib >=1.3.1,<2.0a0 + license: Unlicense + size: 829500 + timestamp: 1725353720793 +- kind: conda + name: libstdcxx + version: 14.1.0 + build: hc0a3c3a_1 + build_number: 1 + subdir: linux-64 + url: https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-14.1.0-hc0a3c3a_1.conda + sha256: 44decb3d23abacf1c6dd59f3c152a7101b7ca565b4ef8872804ceaedcc53a9cd + md5: 9dbb9699ea467983ba8a4ba89b08b066 + depends: + - libgcc 14.1.0 h77fa898_1 + license: GPL-3.0-only WITH GCC-exception-3.1 + license_family: GPL + size: 3892781 + timestamp: 1724801863728 +- kind: conda + name: libstdcxx-ng + version: 14.1.0 + build: h4852527_1 + build_number: 1 + subdir: linux-64 + url: https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-ng-14.1.0-h4852527_1.conda + sha256: a2dc44f97290740cc187bfe94ce543e6eb3c2ea8964d99f189a1d8c97b419b8c + md5: bd2598399a70bb86d8218e95548d735e + depends: + - libstdcxx 14.1.0 hc0a3c3a_1 + license: GPL-3.0-only WITH GCC-exception-3.1 + license_family: GPL + size: 52219 + timestamp: 1724801897766 +- kind: conda + name: libuuid + version: 2.38.1 + build: h0b41bf4_0 + subdir: linux-64 + url: https://conda.anaconda.org/conda-forge/linux-64/libuuid-2.38.1-h0b41bf4_0.conda + sha256: 787eb542f055a2b3de553614b25f09eefb0a0931b0c87dbcce6efdfd92f04f18 + md5: 40b61aab5c7ba9ff276c41cfffe6b80b + depends: + - libgcc-ng >=12 + license: BSD-3-Clause + license_family: BSD + size: 33601 + timestamp: 1680112270483 +- kind: conda + name: libxcrypt + version: 4.4.36 + build: hd590300_1 + build_number: 1 + subdir: linux-64 + url: https://conda.anaconda.org/conda-forge/linux-64/libxcrypt-4.4.36-hd590300_1.conda + sha256: 6ae68e0b86423ef188196fff6207ed0c8195dd84273cb5623b85aa08033a410c + md5: 5aa797f8787fe7a17d1b0821485b5adc + depends: + - libgcc-ng >=12 + license: LGPL-2.1-or-later + size: 100393 + timestamp: 1702724383534 +- kind: conda + name: libzlib + version: 1.3.1 + build: h4ab18f5_1 + build_number: 1 + subdir: linux-64 + url: https://conda.anaconda.org/conda-forge/linux-64/libzlib-1.3.1-h4ab18f5_1.conda + sha256: adf6096f98b537a11ae3729eaa642b0811478f0ea0402ca67b5108fe2cb0010d + md5: 57d7dc60e9325e3de37ff8dffd18e814 + depends: + - libgcc-ng >=12 + constrains: + - zlib 1.3.1 *_1 + license: Zlib + license_family: Other + size: 61574 + timestamp: 1716874187109 +- kind: conda + name: libzlib + version: 1.3.1 + build: hfb2fe0b_1 + build_number: 1 + subdir: osx-arm64 + url: https://conda.anaconda.org/conda-forge/osx-arm64/libzlib-1.3.1-hfb2fe0b_1.conda + sha256: c34365dd37b0eab27b9693af32a1f7f284955517c2cc91f1b88a7ef4738ff03e + md5: 636077128927cf79fd933276dc3aed47 + depends: + - __osx >=11.0 + constrains: + - zlib 1.3.1 *_1 + license: Zlib + license_family: Other + size: 46921 + timestamp: 1716874262512 +- kind: conda + name: llvm-openmp + version: 18.1.8 + build: hde57baf_1 + build_number: 1 + subdir: osx-arm64 + url: https://conda.anaconda.org/conda-forge/osx-arm64/llvm-openmp-18.1.8-hde57baf_1.conda + sha256: 7a76e2932ac77e6314bfa1c4ff83f617c8260313bfed1b8401b508ed3e9d70ba + md5: fe89757e3cd14bb1c6ebd68dac591363 + depends: + - __osx >=11.0 + constrains: + - openmp 18.1.8|18.1.8.* + license: Apache-2.0 WITH LLVM-exception + license_family: APACHE + size: 276263 + timestamp: 1723605341828 +- kind: conda + name: max + version: 24.5.0 + build: release + subdir: noarch + noarch: python + url: https://conda.modular.com/max/noarch/max-24.5.0-release.conda + sha256: 3050d7885a304944afbf93ca9786e56e6df20f0685e1705f88fab045fb5aae70 + md5: 662a61803cd141e857d3b9f821c7bd66 + depends: + - max-core ==24.5.0 release + - max-python >=24.5.0,<25.0a0 + - mojo-jupyter ==24.5.0 release + - mblack ==24.5.0 release + size: 9642 + timestamp: 1726172475909 +- kind: conda + name: max-core + version: 24.5.0 + build: release + subdir: linux-64 + url: https://conda.modular.com/max/linux-64/max-core-24.5.0-release.conda + sha256: 4cd4ab217863a500e9df8112d5e4c335192baa4f527aaaacb925b7818dd2bbe1 + md5: a9b3f9d69310032f687789c475c029f5 + depends: + - mblack ==24.5.0 release + arch: x86_64 + platform: linux + size: 284994357 + timestamp: 1726172475907 +- kind: conda + name: max-core + version: 24.5.0 + build: release + subdir: osx-arm64 + url: https://conda.modular.com/max/osx-arm64/max-core-24.5.0-release.conda + sha256: 8848071dde1f98a4da8e39c90f9210098e7c3c4aaddd0e2255fd9fe1f01df0b7 + md5: fba502bf5142da57735a593ccf35a255 + depends: + - mblack ==24.5.0 release + arch: arm64 + platform: osx + size: 244231803 + timestamp: 1726175523753 +- kind: conda + name: max-python + version: 24.5.0 + build: 3.12release + subdir: linux-64 + url: https://conda.modular.com/max/linux-64/max-python-24.5.0-3.12release.conda + sha256: b5b0f36bb4c91bdff229fc680d7d2e4dd183e9dc90808869408e5883d95199ba + md5: e8dbea1cf138f97c022103a4b41c77bd + depends: + - max-core ==24.5.0 release + - python 3.12.* + - numpy >=1.18,<2.0 + - python_abi 3.12.* *_cp312 + arch: x86_64 + platform: linux + size: 138310039 + timestamp: 1726172475912 +- kind: conda + name: max-python + version: 24.5.0 + build: 3.12release + subdir: osx-arm64 + url: https://conda.modular.com/max/osx-arm64/max-python-24.5.0-3.12release.conda + sha256: e6cdd0477236d49d4f6586d4a66ffe1c5e5cb188535a8ec09ed742eda12cbf5f + md5: f33d8f4cc5c17d893fdb5d6e162c08c6 + depends: + - max-core ==24.5.0 release + - python 3.12.* + - numpy >=1.18,<2.0 + - python_abi 3.12.* *_cp312 + arch: arm64 + platform: osx + size: 125388933 + timestamp: 1726175523755 +- kind: conda + name: mblack + version: 24.5.0 + build: release + subdir: noarch + noarch: python + url: https://conda.modular.com/max/noarch/mblack-24.5.0-release.conda + sha256: 913881fc3aa19db447ed82e898f261a413be9129dc43b9ea600e06030f76dbd5 + md5: 2bc6ce9f257235686dc1b2509cc7198d + depends: + - python >=3.9,<3.13 + - click >=8.0.0 + - mypy_extensions >=0.4.3 + - packaging >=22.0 + - pathspec >=0.9.0 + - platformdirs >=2 + - python + license: MIT + size: 130435 + timestamp: 1726172475910 +- kind: conda + name: mist + version: 0.1.4 + build: h60d57d3_0 + subdir: osx-arm64 + url: https://repo.prefix.dev/mojo-community/osx-arm64/mist-0.1.4-h60d57d3_0.conda + sha256: 24e6e5067edcd7a82db9d50ab0deb3f20b83f158e9ddcd21973ca42495c2c8eb + depends: + - gojo >=0.1.8,<0.2 + - hue >=0.1.4,<0.2 + - max >=24.5.0,<25 + arch: arm64 + platform: osx + license: MIT + size: 474752 + timestamp: 1726265748484 +- kind: conda + name: mist + version: 0.1.4 + build: hb0f4dca_0 + subdir: linux-64 + url: https://repo.prefix.dev/mojo-community/linux-64/mist-0.1.4-hb0f4dca_0.conda + sha256: 36efb61b00cd34c17f1d86ac4c66e575a807d6196cc6625c4a3e6e6f07c1a101 + depends: + - gojo >=0.1.8,<0.2 + - hue >=0.1.4,<0.2 + - max >=24.5.0,<25 + arch: x86_64 + platform: linux + license: MIT + size: 474878 + timestamp: 1726265746139 +- kind: conda + name: mojo-jupyter + version: 24.5.0 + build: release + subdir: noarch + noarch: python + url: https://conda.modular.com/max/noarch/mojo-jupyter-24.5.0-release.conda + sha256: dff2e857eae32ce92fde12a712756d647f0aa312aeb5d79b350b2acbc71a2f96 + md5: 3b7be5cbff5b8015b095e950506be4b3 + depends: + - max-core ==24.5.0 release + - python >=3.9,<3.13 + - jupyter_client >=8.6.2,<8.7 + - python + size: 21595 + timestamp: 1726172475911 +- kind: conda + name: mypy_extensions + version: 1.0.0 + build: pyha770c72_0 + subdir: noarch + noarch: python + url: https://conda.anaconda.org/conda-forge/noarch/mypy_extensions-1.0.0-pyha770c72_0.conda + sha256: f240217476e148e825420c6bc3a0c0efb08c0718b7042fae960400c02af858a3 + md5: 4eccaeba205f0aed9ac3a9ea58568ca3 + depends: + - python >=3.5 + license: MIT + license_family: MIT + size: 10492 + timestamp: 1675543414256 +- kind: conda + name: ncurses + version: '6.5' + build: h7bae524_1 + build_number: 1 + subdir: osx-arm64 + url: https://conda.anaconda.org/conda-forge/osx-arm64/ncurses-6.5-h7bae524_1.conda + sha256: 27d0b9ff78ad46e1f3a6c96c479ab44beda5f96def88e2fe626e0a49429d8afc + md5: cb2b0ea909b97b3d70cd3921d1445e1a + depends: + - __osx >=11.0 + license: X11 AND BSD-3-Clause + size: 802321 + timestamp: 1724658775723 +- kind: conda + name: ncurses + version: '6.5' + build: he02047a_1 + build_number: 1 + subdir: linux-64 + url: https://conda.anaconda.org/conda-forge/linux-64/ncurses-6.5-he02047a_1.conda + sha256: 6a1d5d8634c1a07913f1c525db6455918cbc589d745fac46d9d6e30340c8731a + md5: 70caf8bb6cf39a0b6b7efc885f51c0fe + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc-ng >=12 + license: X11 AND BSD-3-Clause + size: 889086 + timestamp: 1724658547447 +- kind: conda + name: numpy + version: 1.26.4 + build: py312h8442bc7_0 + subdir: osx-arm64 + url: https://conda.anaconda.org/conda-forge/osx-arm64/numpy-1.26.4-py312h8442bc7_0.conda + sha256: c8841d6d6f61fd70ca80682efbab6bdb8606dc77c68d8acabfbd7c222054f518 + md5: d83fc83d589e2625a3451c9a7e21047c + depends: + - libblas >=3.9.0,<4.0a0 + - libcblas >=3.9.0,<4.0a0 + - libcxx >=16 + - liblapack >=3.9.0,<4.0a0 + - python >=3.12,<3.13.0a0 + - python >=3.12,<3.13.0a0 *_cpython + - python_abi 3.12.* *_cp312 + constrains: + - numpy-base <0a0 + license: BSD-3-Clause + license_family: BSD + size: 6073136 + timestamp: 1707226249608 +- kind: conda + name: numpy + version: 1.26.4 + build: py312heda63a1_0 + subdir: linux-64 + url: https://conda.anaconda.org/conda-forge/linux-64/numpy-1.26.4-py312heda63a1_0.conda + sha256: fe3459c75cf84dcef6ef14efcc4adb0ade66038ddd27cadb894f34f4797687d8 + md5: d8285bea2a350f63fab23bf460221f3f + depends: + - libblas >=3.9.0,<4.0a0 + - libcblas >=3.9.0,<4.0a0 + - libgcc-ng >=12 + - liblapack >=3.9.0,<4.0a0 + - libstdcxx-ng >=12 + - python >=3.12,<3.13.0a0 + - python_abi 3.12.* *_cp312 + constrains: + - numpy-base <0a0 + license: BSD-3-Clause + license_family: BSD + size: 7484186 + timestamp: 1707225809722 +- kind: conda + name: openssl + version: 3.3.2 + build: h8359307_0 + subdir: osx-arm64 + url: https://conda.anaconda.org/conda-forge/osx-arm64/openssl-3.3.2-h8359307_0.conda + sha256: 940fa01c4dc6152158fe8943e05e55a1544cab639df0994e3b35937839e4f4d1 + md5: 1773ebccdc13ec603356e8ff1db9e958 + depends: + - __osx >=11.0 + - ca-certificates + license: Apache-2.0 + license_family: Apache + size: 2882450 + timestamp: 1725410638874 +- kind: conda + name: openssl + version: 3.3.2 + build: hb9d3cd8_0 + subdir: linux-64 + url: https://conda.anaconda.org/conda-forge/linux-64/openssl-3.3.2-hb9d3cd8_0.conda + sha256: cee91036686419f6dd6086902acf7142b4916e1c4ba042e9ca23e151da012b6d + md5: 4d638782050ab6faa27275bed57e9b4e + depends: + - __glibc >=2.17,<3.0.a0 + - ca-certificates + - libgcc >=13 + license: Apache-2.0 + license_family: Apache + size: 2891789 + timestamp: 1725410790053 +- kind: conda + name: packaging + version: '24.1' + build: pyhd8ed1ab_0 + subdir: noarch + noarch: python + url: https://conda.anaconda.org/conda-forge/noarch/packaging-24.1-pyhd8ed1ab_0.conda + sha256: 36aca948219e2c9fdd6d80728bcc657519e02f06c2703d8db3446aec67f51d81 + md5: cbe1bb1f21567018ce595d9c2be0f0db + depends: + - python >=3.8 + license: Apache-2.0 + license_family: APACHE + size: 50290 + timestamp: 1718189540074 +- kind: conda + name: pathspec + version: 0.12.1 + build: pyhd8ed1ab_0 + subdir: noarch + noarch: python + url: https://conda.anaconda.org/conda-forge/noarch/pathspec-0.12.1-pyhd8ed1ab_0.conda + sha256: 4e534e66bfe8b1e035d2169d0e5b185450546b17e36764272863e22e0370be4d + md5: 17064acba08d3686f1135b5ec1b32b12 + depends: + - python >=3.7 + license: MPL-2.0 + license_family: MOZILLA + size: 41173 + timestamp: 1702250135032 +- kind: conda + name: platformdirs + version: 4.3.2 + build: pyhd8ed1ab_0 + subdir: noarch + noarch: python + url: https://conda.anaconda.org/conda-forge/noarch/platformdirs-4.3.2-pyhd8ed1ab_0.conda + sha256: 3aef5bb863a2db94e47272fd5ec5a5e4b240eafba79ebb9df7a162797cf035a3 + md5: e1a2dfcd5695f0744f1bcd3bbfe02523 + depends: + - python >=3.8 + license: MIT + license_family: MIT + size: 20623 + timestamp: 1725821846879 +- kind: conda + name: python + version: 3.12.5 + build: h2ad013b_0_cpython + subdir: linux-64 + url: https://conda.anaconda.org/conda-forge/linux-64/python-3.12.5-h2ad013b_0_cpython.conda + sha256: e2aad83838988725d4ffba4e9717b9328054fd18a668cff3377e0c50f109e8bd + md5: 9c56c4df45f6571b13111d8df2448692 + depends: + - __glibc >=2.17,<3.0.a0 + - bzip2 >=1.0.8,<2.0a0 + - ld_impl_linux-64 >=2.36.1 + - libexpat >=2.6.2,<3.0a0 + - libffi >=3.4,<4.0a0 + - libgcc-ng >=12 + - libnsl >=2.0.1,<2.1.0a0 + - libsqlite >=3.46.0,<4.0a0 + - libuuid >=2.38.1,<3.0a0 + - libxcrypt >=4.4.36 + - libzlib >=1.3.1,<2.0a0 + - ncurses >=6.5,<7.0a0 + - openssl >=3.3.1,<4.0a0 + - readline >=8.2,<9.0a0 + - tk >=8.6.13,<8.7.0a0 + - tzdata + - xz >=5.2.6,<6.0a0 + constrains: + - python_abi 3.12.* *_cp312 + license: Python-2.0 + size: 31663253 + timestamp: 1723143721353 +- kind: conda + name: python + version: 3.12.6 + build: h739c21a_0_cpython + subdir: osx-arm64 + url: https://conda.anaconda.org/conda-forge/osx-arm64/python-3.12.6-h739c21a_0_cpython.conda + sha256: 7dc75f4a7f800426e39ba219a1202c00b002cd0c792e34e077d3d7c145ef0199 + md5: 1d0f564edfc8121b35a4dc2d25b62863 + depends: + - __osx >=11.0 + - bzip2 >=1.0.8,<2.0a0 + - libexpat >=2.6.3,<3.0a0 + - libffi >=3.4,<4.0a0 + - libsqlite >=3.46.1,<4.0a0 + - libzlib >=1.3.1,<2.0a0 + - ncurses >=6.5,<7.0a0 + - openssl >=3.3.2,<4.0a0 + - readline >=8.2,<9.0a0 + - tk >=8.6.13,<8.7.0a0 + - tzdata + - xz >=5.2.6,<6.0a0 + constrains: + - python_abi 3.12.* *_cp312 + license: Python-2.0 + size: 12877861 + timestamp: 1726030796871 +- kind: conda + name: python-dateutil + version: 2.9.0 + build: pyhd8ed1ab_0 + subdir: noarch + noarch: python + url: https://conda.anaconda.org/conda-forge/noarch/python-dateutil-2.9.0-pyhd8ed1ab_0.conda + sha256: f3ceef02ac164a8d3a080d0d32f8e2ebe10dd29e3a685d240e38b3599e146320 + md5: 2cf4264fffb9e6eff6031c5b6884d61c + depends: + - python >=3.7 + - six >=1.5 + license: Apache-2.0 + license_family: APACHE + size: 222742 + timestamp: 1709299922152 +- kind: conda + name: python_abi + version: '3.12' + build: 5_cp312 + build_number: 5 + subdir: linux-64 + url: https://conda.anaconda.org/conda-forge/linux-64/python_abi-3.12-5_cp312.conda + sha256: d10e93d759931ffb6372b45d65ff34d95c6000c61a07e298d162a3bc2accebb0 + md5: 0424ae29b104430108f5218a66db7260 + constrains: + - python 3.12.* *_cpython + license: BSD-3-Clause + license_family: BSD + size: 6238 + timestamp: 1723823388266 +- kind: conda + name: python_abi + version: '3.12' + build: 5_cp312 + build_number: 5 + subdir: osx-arm64 + url: https://conda.anaconda.org/conda-forge/osx-arm64/python_abi-3.12-5_cp312.conda + sha256: 49d624e4b809c799d2bf257b22c23cf3fc4460f5570d9a58e7ad86350aeaa1f4 + md5: b76f9b1c862128e56ac7aa8cd2333de9 + constrains: + - python 3.12.* *_cpython + license: BSD-3-Clause + license_family: BSD + size: 6278 + timestamp: 1723823099686 +- kind: conda + name: pyzmq + version: 26.2.0 + build: py312hbf22597_2 + build_number: 2 + subdir: linux-64 + url: https://conda.anaconda.org/conda-forge/linux-64/pyzmq-26.2.0-py312hbf22597_2.conda + sha256: a2431644cdef4111f7120565090114f52897e687e83c991bd76a3baef8de77c4 + md5: 44f46ddfdd01d242d2fff2d69a0d7cba + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=13 + - libsodium >=1.0.20,<1.0.21.0a0 + - libstdcxx >=13 + - python >=3.12,<3.13.0a0 + - python_abi 3.12.* *_cp312 + - zeromq >=4.3.5,<4.4.0a0 + license: BSD-3-Clause + license_family: BSD + size: 378667 + timestamp: 1725449078945 +- kind: conda + name: pyzmq + version: 26.2.0 + build: py312hc6335d2_2 + build_number: 2 + subdir: osx-arm64 + url: https://conda.anaconda.org/conda-forge/osx-arm64/pyzmq-26.2.0-py312hc6335d2_2.conda + sha256: 8d46c0f1af50989f308b9da68e6123bc3560f3a3a741b4e7cb8867c603b5a9f1 + md5: ca61d76f24d66c2938af62e882c9a02d + depends: + - __osx >=11.0 + - libcxx >=17 + - libsodium >=1.0.20,<1.0.21.0a0 + - python >=3.12,<3.13.0a0 + - python >=3.12,<3.13.0a0 *_cpython + - python_abi 3.12.* *_cp312 + - zeromq >=4.3.5,<4.4.0a0 + license: BSD-3-Clause + license_family: BSD + size: 359594 + timestamp: 1725449428595 +- kind: conda + name: readline + version: '8.2' + build: h8228510_1 + build_number: 1 + subdir: linux-64 + url: https://conda.anaconda.org/conda-forge/linux-64/readline-8.2-h8228510_1.conda + sha256: 5435cf39d039387fbdc977b0a762357ea909a7694d9528ab40f005e9208744d7 + md5: 47d31b792659ce70f470b5c82fdfb7a4 + depends: + - libgcc-ng >=12 + - ncurses >=6.3,<7.0a0 + license: GPL-3.0-only + license_family: GPL + size: 281456 + timestamp: 1679532220005 +- kind: conda + name: readline + version: '8.2' + build: h92ec313_1 + build_number: 1 + subdir: osx-arm64 + url: https://conda.anaconda.org/conda-forge/osx-arm64/readline-8.2-h92ec313_1.conda + sha256: a1dfa679ac3f6007362386576a704ad2d0d7a02e98f5d0b115f207a2da63e884 + md5: 8cbb776a2f641b943d413b3e19df71f4 + depends: + - ncurses >=6.3,<7.0a0 + license: GPL-3.0-only + license_family: GPL + size: 250351 + timestamp: 1679532511311 +- kind: conda + name: six + version: 1.16.0 + build: pyh6c4a22f_0 + subdir: noarch + noarch: python + url: https://conda.anaconda.org/conda-forge/noarch/six-1.16.0-pyh6c4a22f_0.tar.bz2 + sha256: a85c38227b446f42c5b90d9b642f2c0567880c15d72492d8da074a59c8f91dd6 + md5: e5f25f8dbc060e9a8d912e432202afc2 + depends: + - python + license: MIT + license_family: MIT + size: 14259 + timestamp: 1620240338595 +- kind: conda + name: tk + version: 8.6.13 + build: h5083fa2_1 + build_number: 1 + subdir: osx-arm64 + url: https://conda.anaconda.org/conda-forge/osx-arm64/tk-8.6.13-h5083fa2_1.conda + sha256: 72457ad031b4c048e5891f3f6cb27a53cb479db68a52d965f796910e71a403a8 + md5: b50a57ba89c32b62428b71a875291c9b + depends: + - libzlib >=1.2.13,<2.0.0a0 + license: TCL + license_family: BSD + size: 3145523 + timestamp: 1699202432999 +- kind: conda + name: tk + version: 8.6.13 + build: noxft_h4845f30_101 + build_number: 101 + subdir: linux-64 + url: https://conda.anaconda.org/conda-forge/linux-64/tk-8.6.13-noxft_h4845f30_101.conda + sha256: e0569c9caa68bf476bead1bed3d79650bb080b532c64a4af7d8ca286c08dea4e + md5: d453b98d9c83e71da0741bb0ff4d76bc + depends: + - libgcc-ng >=12 + - libzlib >=1.2.13,<2.0.0a0 + license: TCL + license_family: BSD + size: 3318875 + timestamp: 1699202167581 +- kind: conda + name: tornado + version: 6.4.1 + build: py312h024a12e_1 + build_number: 1 + subdir: osx-arm64 + url: https://conda.anaconda.org/conda-forge/osx-arm64/tornado-6.4.1-py312h024a12e_1.conda + sha256: 5eefede1d8a2f55892bc582dbcb574b1806f19bc1e3939ce56b79721b9406db7 + md5: 967bc97bb9e258993289546479af971f + depends: + - __osx >=11.0 + - python >=3.12,<3.13.0a0 + - python >=3.12,<3.13.0a0 *_cpython + - python_abi 3.12.* *_cp312 + license: Apache-2.0 + license_family: Apache + size: 841722 + timestamp: 1724956439106 +- kind: conda + name: tornado + version: 6.4.1 + build: py312h66e93f0_1 + build_number: 1 + subdir: linux-64 + url: https://conda.anaconda.org/conda-forge/linux-64/tornado-6.4.1-py312h66e93f0_1.conda + sha256: c0c9cc7834e8f43702956afaa5af7b0639c4835c285108a43e6b91687ce53ab8 + md5: af648b62462794649066366af4ecd5b0 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=13 + - python >=3.12,<3.13.0a0 + - python_abi 3.12.* *_cp312 + license: Apache-2.0 + license_family: Apache + size: 837665 + timestamp: 1724956252424 +- kind: conda + name: traitlets + version: 5.14.3 + build: pyhd8ed1ab_0 + subdir: noarch + noarch: python + url: https://conda.anaconda.org/conda-forge/noarch/traitlets-5.14.3-pyhd8ed1ab_0.conda + sha256: 8a64fa0f19022828513667c2c7176cfd125001f3f4b9bc00d33732e627dd2592 + md5: 3df84416a021220d8b5700c613af2dc5 + depends: + - python >=3.8 + license: BSD-3-Clause + license_family: BSD + size: 110187 + timestamp: 1713535244513 +- kind: conda + name: tzdata + version: 2024a + build: h8827d51_1 + build_number: 1 + subdir: noarch + noarch: generic + url: https://conda.anaconda.org/conda-forge/noarch/tzdata-2024a-h8827d51_1.conda + sha256: 7d21c95f61319dba9209ca17d1935e6128af4235a67ee4e57a00908a1450081e + md5: 8bfdead4e0fff0383ae4c9c50d0531bd + license: LicenseRef-Public-Domain + size: 124164 + timestamp: 1724736371498 +- kind: conda + name: weave + version: 0.1.1 + build: h60d57d3_0 + subdir: osx-arm64 + url: https://repo.prefix.dev/mojo-community/osx-arm64/weave-0.1.1-h60d57d3_0.conda + sha256: b7cb567a292d6bdb8a41ca8dc917595c825798ab2fb02e9c69fac8e2c0f77e3d + depends: + - max >=24.5.0,<25 + - gojo >=0.1.8,<0.2 + arch: arm64 + platform: osx + license: MIT + size: 423224 + timestamp: 1726266849700 +- kind: conda + name: weave + version: 0.1.1 + build: hb0f4dca_0 + subdir: linux-64 + url: https://repo.prefix.dev/mojo-community/linux-64/weave-0.1.1-hb0f4dca_0.conda + sha256: b7cac210c54f44f43f70a594e2931fb6f092ee1698a6b64b2836e435183068ea + depends: + - max >=24.5.0,<25 + - gojo >=0.1.8,<0.2 + arch: x86_64 + platform: linux + license: MIT + size: 423401 + timestamp: 1726266848390 +- kind: conda + name: xz + version: 5.2.6 + build: h166bdaf_0 + subdir: linux-64 + url: https://conda.anaconda.org/conda-forge/linux-64/xz-5.2.6-h166bdaf_0.tar.bz2 + sha256: 03a6d28ded42af8a347345f82f3eebdd6807a08526d47899a42d62d319609162 + md5: 2161070d867d1b1204ea749c8eec4ef0 + depends: + - libgcc-ng >=12 + license: LGPL-2.1 and GPL-2.0 + size: 418368 + timestamp: 1660346797927 +- kind: conda + name: xz + version: 5.2.6 + build: h57fd34a_0 + subdir: osx-arm64 + url: https://conda.anaconda.org/conda-forge/osx-arm64/xz-5.2.6-h57fd34a_0.tar.bz2 + sha256: 59d78af0c3e071021cfe82dc40134c19dab8cdf804324b62940f5c8cd71803ec + md5: 39c6b54e94014701dd157f4f576ed211 + license: LGPL-2.1 and GPL-2.0 + size: 235693 + timestamp: 1660346961024 +- kind: conda + name: zeromq + version: 4.3.5 + build: h64debc3_5 + build_number: 5 + subdir: osx-arm64 + url: https://conda.anaconda.org/conda-forge/osx-arm64/zeromq-4.3.5-h64debc3_5.conda + sha256: b4ba544a04129472651a5df3b8906ed68e7f43bf23e724fd0e368218083c920c + md5: c29dbe9343a0b55b027fa645644c59d9 + depends: + - __osx >=11.0 + - krb5 >=1.21.3,<1.22.0a0 + - libcxx >=17 + - libsodium >=1.0.20,<1.0.21.0a0 + license: MPL-2.0 + license_family: MOZILLA + size: 296355 + timestamp: 1725430145243 +- kind: conda + name: zeromq + version: 4.3.5 + build: ha4adb4c_5 + build_number: 5 + subdir: linux-64 + url: https://conda.anaconda.org/conda-forge/linux-64/zeromq-4.3.5-ha4adb4c_5.conda + sha256: dd48adc07fcd029c86fbf82e68d0e4818c7744b768e08139379920b56b582814 + md5: e8372041ebb377237db9d0d24c7b5962 + depends: + - __glibc >=2.17,<3.0.a0 + - krb5 >=1.21.3,<1.22.0a0 + - libgcc >=13 + - libsodium >=1.0.20,<1.0.21.0a0 + - libstdcxx >=13 + license: MPL-2.0 + license_family: MOZILLA + size: 353159 + timestamp: 1725429777124 +- kind: conda + name: zipp + version: 3.20.2 + build: pyhd8ed1ab_0 + subdir: noarch + noarch: python + url: https://conda.anaconda.org/conda-forge/noarch/zipp-3.20.2-pyhd8ed1ab_0.conda + sha256: 1e84fcfa41e0afdd87ff41e6fbb719c96a0e098c1f79be342293ab0bd8dea322 + md5: 4daaed111c05672ae669f7036ee5bba3 + depends: + - python >=3.8 + license: MIT + license_family: MIT + size: 21409 + timestamp: 1726248679175 diff --git a/mog/extensions.mojo b/mog/extensions.mojo deleted file mode 100644 index 35288c0..0000000 --- a/mog/extensions.mojo +++ /dev/null @@ -1,17 +0,0 @@ -# Strings -@always_inline -fn split(text: String, sep: String, max_split: Int = -1) -> List[String]: - try: - return text.split(sep, max_split) - except: - return List[String](text) - - -@always_inline -fn join(separator: String, iterable: List[String]) -> String: - var result: String = "" - for i in range(len(iterable)): - result += iterable[i] - if i != len(iterable) - 1: - result += separator - return result diff --git a/mojoproject.toml b/mojoproject.toml new file mode 100644 index 0000000..67c9a64 --- /dev/null +++ b/mojoproject.toml @@ -0,0 +1,21 @@ +[project] +authors = ["Mikhail Tavarez "] +channels = ["https://repo.prefix.dev/mojo-community", "conda-forge", "https://conda.modular.com/max"] +description = "Style definitions for nice terminal layouts. Built with TUIs in mind." +name = "mog" +platforms = ["osx-arm64", "linux-64"] +version = "0.1.5" + +[tasks] +tests = "bash scripts/tests.sh" +examples = "bash scripts/examples.sh" +benchmarks = "bash scripts/benchmarks.sh" +build = { cmd = "rattler-build build -r src -c https://repo.prefix.dev/mojo-community -c https://conda.modular.com/max -c conda-forge --skip-existing=all", env = {MODULAR_MOJO_NIGHTLY_IMPORT_PATH = "$CONDA_PREFIX/lib/mojo"} } +publish = { cmd = "bash scripts/publish.sh", env = { PREFIX_API_KEY = "$PREFIX_API_KEY" } } + +[dependencies] +max = ">=24.5.0,<25" +gojo = ">=0.1.9,<0.2" +weave = ">=0.1.1,<0.2" +mist = ">=0.1.4,<0.2" + diff --git a/run_examples.sh b/run_examples.sh deleted file mode 100644 index 0f2c96e..0000000 --- a/run_examples.sh +++ /dev/null @@ -1,17 +0,0 @@ -#!/bin/bash -mkdir ./temp -mojo package mog -I ./external -o ./temp/mog.mojopkg - -echo -e "Building binaries for all examples...\n" -mojo build examples/readme/basic.mojo -o temp/basic -mojo build examples/readme/layout.mojo -o temp/layout -mojo build examples/table/ansi.mojo -o temp/ansi - -echo -e "Executing examples...\n" -cd temp -./basic -./layout -./ansi - -cd .. -rm -R ./temp diff --git a/scripts/benchmarks.sh b/scripts/benchmarks.sh new file mode 100755 index 0000000..ed4889a --- /dev/null +++ b/scripts/benchmarks.sh @@ -0,0 +1,15 @@ +#!/bin/bash + +TEMP_DIR=~/tmp +PACKAGE_NAME=mog +mkdir -p $TEMP_DIR + +echo "[INFO] Building $PACKAGE_NAME package and running benchmarks." +cp -a benchmarks/. $TEMP_DIR +magic run mojo package src/$PACKAGE_NAME -o $TEMP_DIR/$PACKAGE_NAME.mojopkg + +echo "[INFO] Running benchmarks..." +magic run mojo $TEMP_DIR/run.mojo + +echo "[INFO] Cleaning up the benchmarks directory." +rm -R $TEMP_DIR diff --git a/scripts/examples.sh b/scripts/examples.sh new file mode 100755 index 0000000..a643127 --- /dev/null +++ b/scripts/examples.sh @@ -0,0 +1,23 @@ +#!/bin/bash + +TEMP_DIR=~/tmp +PACKAGE_NAME=mog +mkdir -p $TEMP_DIR + +echo "[INFO] Building $PACKAGE_NAME package and example binaries." +cp -a examples/. $TEMP_DIR +magic run mojo package src/$PACKAGE_NAME -o $TEMP_DIR/$PACKAGE_NAME.mojopkg +magic run mojo build $TEMP_DIR/basic.mojo -o $TEMP_DIR/basic +magic run mojo build $TEMP_DIR/layout.mojo -o $TEMP_DIR/layout +magic run mojo build $TEMP_DIR/ansi.mojo -o $TEMP_DIR/ansi +magic run mojo run $TEMP_DIR/pokemon.mojo # temporary, it segfaults otherwise +# magic run mojo build $TEMP_DIR/pokemon.mojo -o $TEMP_DIR/pokemon + +echo "[INFO] Running examples..." +$TEMP_DIR/basic +$TEMP_DIR/layout +$TEMP_DIR/ansi +# $TEMP_DIR/pokemon + +echo "[INFO] Cleaning up the example directory." +rm -R $TEMP_DIR diff --git a/scripts/publish.sh b/scripts/publish.sh new file mode 100644 index 0000000..e081260 --- /dev/null +++ b/scripts/publish.sh @@ -0,0 +1,8 @@ +#!/bin/bash + +# ignore errors because we want to ignore duplicate packages +for file in $CONDA_BLD_PATH/**/*.conda; do + magic run rattler-build upload prefix -c "mojo-community" "$file" || true +done + +rm $CONDA_BLD_PATH/**/*.conda \ No newline at end of file diff --git a/scripts/tests.sh b/scripts/tests.sh new file mode 100755 index 0000000..0d8e8d1 --- /dev/null +++ b/scripts/tests.sh @@ -0,0 +1,15 @@ +#!/bin/bash + +TEMP_DIR=~/tmp +PACKAGE_NAME=mog +mkdir -p $TEMP_DIR + +echo "[INFO] Building $PACKAGE_NAME package and copying tests." +cp -a test/. $TEMP_DIR +magic run mojo package src/$PACKAGE_NAME -o $TEMP_DIR/$PACKAGE_NAME.mojopkg + +echo "[INFO] Running tests..." +magic run mojo test $TEMP_DIR + +echo "[INFO] Cleaning up the test directory." +rm -R $TEMP_DIR diff --git a/mog/__init__.mojo b/src/mog/__init__.mojo similarity index 57% rename from mog/__init__.mojo rename to src/mog/__init__.mojo index 8fdd020..bbd60e8 100644 --- a/mog/__init__.mojo +++ b/src/mog/__init__.mojo @@ -1,6 +1,7 @@ -from .style import Style, NO_TAB_CONVERSION, get_lines +from .style import Style, NO_TAB_CONVERSION from .border import ( Border, + NORMAL_BORDER, ROUNDED_BORDER, DOUBLE_BORDER, ASCII_BORDER, @@ -25,7 +26,25 @@ from .color import ( CompleteAdaptiveColor, AnyTerminalColor, ) +from .renderer import Renderer +from .join import join_horizontal, join_vertical alias WHITESPACE = String(" ") alias NEWLINE = String("\n") + +alias TRUE_COLOR = mist.TRUE_COLOR +alias ANSI256 = mist.ANSI256 +alias ANSI = mist.ANSI +alias ASCII = mist.ASCII + +fn raw_print(text: String) -> None: + """Prints text without any formatting. + + Args: + text: The text to print. + """ + try: + print(text.split("@").__str__()) + except: + print(text) diff --git a/mog/align.mojo b/src/mog/align.mojo similarity index 76% rename from mog/align.mojo rename to src/mog/align.mojo index aac5273..4edae9f 100644 --- a/mog/align.mojo +++ b/src/mog/align.mojo @@ -1,13 +1,12 @@ -from external.weave.ansi.ansi import printable_rune_width -import external.mist -from external.gojo.strings import StringBuilder +from collections import Optional +from weave.ansi import printable_rune_width +import mist +from gojo.strings import StringBuilder import .position -from .extensions import split +from .extensions import get_lines -fn align_text_horizontal( - text: String, pos: position.Position, width: Int, style: Optional[mist.Style] = None -) -> String: +fn align_text_horizontal(text: String, pos: position.Position, width: Int, style: Optional[mist.Style] = None) -> String: """Perform text alignment. If the string is multi-lined, we also make all lines the same width by padding them with spaces. If a termenv style is passed, use that to style the spaces added. @@ -28,7 +27,7 @@ fn align_text_horizontal( var aligned_text = StringBuilder(capacity=len(text)) for i in range(len(lines)): var line = lines[i] - var line_width = printable_rune_width(line) + var line_width = printable_rune_width(lines[i]) var short_amount = widest_line - line_width # difference from the widest line short_amount += max(0, width - (short_amount + line_width)) # difference from the total width, if set @@ -36,9 +35,8 @@ fn align_text_horizontal( if pos == position.right: var spaces = WHITESPACE * short_amount - # Removed the nil check before rendering the spaces in whatever style for now. if style: - spaces = style.value()[].render(spaces) + spaces = style.value().render(spaces) line = spaces + line elif pos == position.center: # Note: remainder goes on the right. @@ -49,24 +47,24 @@ fn align_text_horizontal( var right_spaces = WHITESPACE * int(right) if style: - left_spaces = style.value()[].render(left_spaces) - right_spaces = style.value()[].render(right_spaces) + left_spaces = style.value().render(left_spaces) + right_spaces = style.value().render(right_spaces) line = left_spaces + line + right_spaces elif pos == position.left: var spaces = WHITESPACE * int(short_amount) if style: - spaces = style.value()[].render(spaces) + spaces = style.value().render(spaces) line += spaces _ = aligned_text.write_string(line) if i < len(lines) - 1: - _ = aligned_text.write_string("\n") + _ = aligned_text.write_string(NEWLINE) return str(aligned_text) fn align_text_vertical(text: String, pos: position.Position, height: Int) -> String: - var text_height = text.count("\n") + 1 + var text_height = text.count(NEWLINE) + 1 if height < text_height: return text diff --git a/mog/border.mojo b/src/mog/border.mojo similarity index 99% rename from mog/border.mojo rename to src/mog/border.mojo index 383a46a..2dbdf1c 100644 --- a/mog/border.mojo +++ b/src/mog/border.mojo @@ -1,4 +1,4 @@ -from external.weave.ansi.ansi import printable_rune_width +from weave.ansi import printable_rune_width @value diff --git a/mog/color.mojo b/src/mog/color.mojo similarity index 99% rename from mog/color.mojo rename to src/mog/color.mojo index 7329881..d29b093 100644 --- a/mog/color.mojo +++ b/src/mog/color.mojo @@ -1,6 +1,6 @@ from utils.variant import Variant from .renderer import Renderer -import external.mist +import mist trait TerminalColor(CollectionElement): @@ -49,7 +49,6 @@ struct Color(TerminalColor): var ansi_color = mog.Color(21) var hex_color = mog.Color(0x0000ff) ``` - . """ var value: UInt32 diff --git a/src/mog/extensions.mojo b/src/mog/extensions.mojo new file mode 100644 index 0000000..b4549fa --- /dev/null +++ b/src/mog/extensions.mojo @@ -0,0 +1,85 @@ +from weave.ansi import printable_rune_width +from utils import StringSlice + +# fn split_lines(text: StringSlice, keepends: Bool = False) -> List[String]: +# """Split the string at line boundaries. This corresponds to Python's +# [universal newlines]( +# https://docs.python.org/3/library/stdtypes.html#str.splitlines) +# `"\\t\\n\\r\\r\\n\\f\\v\\x1c\\x1d\\x1e\\x85\\u2028\\u2029"`. + +# Args: +# keepends: If True, line breaks are kept in the resulting strings. + +# Returns: +# A List of Strings containing the input split by line boundaries. +# """ +# var output = List[String]() +# var length = text.byte_length() +# var current_offset = 0 +# var ptr = text.unsafe_ptr() + +# while current_offset < length: +# var eol_location = length - current_offset +# var eol_length = 0 +# var curr_ptr = ptr.offset(current_offset) + +# for i in range(current_offset, length): +# var read_ahead = 3 if i < length - 2 else ( +# 2 if i < length - 1 else 1 +# ) +# var res = _is_newline_start(ptr.offset(i), read_ahead) +# if res[0]: +# eol_location = i - current_offset +# eol_length = res[1] +# break + +# var str_len: Int +# var end_of_string = False +# if current_offset >= length: +# end_of_string = True +# str_len = 0 +# elif keepends: +# str_len = eol_location + eol_length +# else: +# str_len = eol_location + +# output.append( +# String(Self(unsafe_from_utf8_ptr=curr_ptr, len=str_len)) +# ) + +# if end_of_string: +# break +# current_offset += eol_location + eol_length + +# return output^ + + +fn get_lines(text: String) -> Tuple[List[String], Int]: + """Split a string into lines. + + Args: + text: The string to split. + + Returns: + A tuple containing the lines and the width of the widest line. + """ + var lines = split_lines(text) + var widest_line: Int = 0 + for i in range(len(lines)): + if printable_rune_width(lines[i]) > widest_line: + widest_line = printable_rune_width(lines[i]) + + return lines, widest_line + + +fn split_lines(text: String) -> List[String]: + return text.as_string_slice().splitlines() + + +fn join(separator: String, iterable: List[String]) -> String: + var result: String = "" + for i in range(len(iterable)): + result += iterable[i] + if i != len(iterable) - 1: + result += separator + return result diff --git a/mog/join.mojo b/src/mog/join.mojo similarity index 97% rename from mog/join.mojo rename to src/mog/join.mojo index 308799d..9709c65 100644 --- a/mog/join.mojo +++ b/src/mog/join.mojo @@ -1,8 +1,8 @@ import math -from external.weave.ansi.ansi import printable_rune_width -from external.gojo.strings import StringBuilder +from weave.ansi import printable_rune_width +from gojo.strings import StringBuilder from .position import Position, top, bottom, left, right, center -from .extensions import split +from .extensions import split_lines fn join_horizontal(pos: Position, *strs: String) -> String: @@ -41,7 +41,7 @@ fn join_horizontal(pos: Position, *strs: String) -> String: # Break text blocks into lines and get max widths for each text block for i in range(len(strs)): var s = strs[i] - var lines = split(s, "\n") + var lines = split_lines(s) var widest: Int = 0 for i in range(len(lines)): var rune_count = printable_rune_width(lines[i]) @@ -131,7 +131,7 @@ fn join_horizontal(pos: Position, strs: List[String]) -> String: # Break text blocks into lines and get max widths for each text block for i in range(len(strs)): var s = strs[i] - var lines = split(s, "\n") + var lines = split_lines(s) var widest: Int = 0 for i in range(len(lines)): var rune_count = printable_rune_width(lines[i]) @@ -221,7 +221,7 @@ fn join_vertical(pos: Position, *strs: String) -> String: for i in range(len(strs)): var s = strs[i] - var lines = split(s, "\n") + var lines = split_lines(s) var widest: Int = 0 for i in range(len(lines)): var rune_count = printable_rune_width(lines[i]) @@ -299,7 +299,7 @@ fn join_vertical(pos: Position, strs: List[String]) -> String: for i in range(len(strs)): var s = strs[i] - var lines = split(s, "\n") + var lines = split_lines(s) var widest: Int = 0 for i in range(len(lines)): var rune_count = printable_rune_width(lines[i]) diff --git a/mog/position.mojo b/src/mog/position.mojo similarity index 100% rename from mog/position.mojo rename to src/mog/position.mojo diff --git a/mog/renderer.mojo b/src/mog/renderer.mojo similarity index 98% rename from mog/renderer.mojo rename to src/mog/renderer.mojo index 7301146..75f0670 100644 --- a/mog/renderer.mojo +++ b/src/mog/renderer.mojo @@ -1,9 +1,10 @@ -import external.mist -from external.gojo.strings import StringBuilder -import external.weave.ansi +from collections import Optional +import mist +from gojo.strings import StringBuilder +import weave.ansi from .whitespace import WhitespaceOption, new_whitespace import .position -from .extensions import split +from .extensions import split_lines # TODO: Cannot handle characters with a printable width of 2 or more. Like east asian characters (Kanji, etc.). @@ -24,7 +25,7 @@ struct Renderer: explicit_background_color: Bool = False, ): if color_profile: - self.color_profile = mist.Profile(color_profile.value()[]) + self.color_profile = mist.Profile(color_profile.value()) else: self.color_profile = mist.Profile() self.dark_background = dark_background @@ -153,7 +154,7 @@ struct Renderer: Returns: The string with the text placed in the block. """ - var lines = text.split("\n") + var lines = split_lines(text) var content_width: Int = 0 for i in range(len(lines)): if ansi.printable_rune_width(lines[i]) > content_width: @@ -216,7 +217,7 @@ struct Renderer: Returns: The string with the text placed in the block. """ - var lines = split(text, "\n") + var lines = split_lines(text) var content_width: Int = 0 for i in range(len(lines)): if ansi.printable_rune_width(lines[i]) > content_width: @@ -286,7 +287,7 @@ struct Renderer: options.append(opt) var white_space = new_whitespace(self, options) - var lines = split(text, "\n") + var lines = split_lines(text) var width: Int = 0 for i in range(len(lines)): if ansi.printable_rune_width(lines[i]) > width: @@ -355,7 +356,7 @@ struct Renderer: var white_space = new_whitespace(self, opts) - var lines = split(text, "\n") + var lines = split_lines(text) var width: Int = 0 for i in range(len(lines)): if ansi.printable_rune_width(lines[i]) > width: diff --git a/mog/size.mojo b/src/mog/size.mojo similarity index 92% rename from mog/size.mojo rename to src/mog/size.mojo index d7c31c0..4882113 100644 --- a/mog/size.mojo +++ b/src/mog/size.mojo @@ -1,5 +1,5 @@ -from external.weave.ansi import ansi -from .extensions import split +import weave.ansi +from .extensions import split_lines fn get_width(text: String) -> Int: @@ -15,7 +15,7 @@ fn get_width(text: String) -> Int: Returns: The width of the string in cells. """ - var strings = split(text, "\n") + var strings = split_lines(text) var width: Int = 0 for i in range(len(strings)): var l = strings[i] @@ -40,7 +40,7 @@ fn get_height(text: String) -> Int: """ var height = 1 for i in range(len(text)): - if text[i] == "\n": + if text[i] == NEWLINE: height += 1 return height diff --git a/mog/style.mojo b/src/mog/style.mojo similarity index 96% rename from mog/style.mojo rename to src/mog/style.mojo index af2f3e3..77849de 100644 --- a/mog/style.mojo +++ b/src/mog/style.mojo @@ -1,3 +1,4 @@ +from collections import Optional from .renderer import Renderer from .position import Position from .border import ( @@ -16,7 +17,7 @@ from .border import ( STAR_BORDER, PLUS_BORDER, ) -from .extensions import join, split +from .extensions import join, split_lines, get_lines from .align import align_text_horizontal, align_text_vertical from .color import ( AnyTerminalColor, @@ -28,10 +29,10 @@ from .color import ( CompleteColor, CompleteAdaptiveColor, ) -from external.weave import wrap, wordwrap, truncate -from external.weave.ansi.ansi import printable_rune_width -import external.mist -from external.gojo.strings import StringBuilder, Reader +from weave import wrap, wordwrap, truncate +from weave.ansi import printable_rune_width +import mist +from gojo.strings import StringBuilder, Reader alias TAB_WIDTH: Int = 4 @@ -99,25 +100,6 @@ alias UNDERLINE_SPACES_KEY: PropertyKey = 41 alias CROSSOUT_SPACES_KEY: PropertyKey = 42 -fn get_lines(text: String) -> Tuple[List[String], Int]: - """Split a string into lines. - - Args: - text: The string to split. - - Returns: - A tuple containing the lines and the width of the widest line. - """ - var lines = split(text, "\n") - - var widest_line: Int = 0 - for i in range(len(lines)): - if printable_rune_width(lines[i]) > widest_line: - widest_line = printable_rune_width(lines[i]) - - return lines, widest_line - - # Apply left padding. fn pad(text: String, n: Int, style: mist.Style) -> String: if n == 0: @@ -125,7 +107,7 @@ fn pad(text: String, n: Int, style: mist.Style) -> String: var sp = style.render(WHITESPACE * abs(n)) var builder = StringBuilder(capacity=int(len(text) * 1.5)) - var lines = split(text, "\n") + var lines = split_lines(text) for i in range(len(lines)): if n > 0: @@ -136,7 +118,7 @@ fn pad(text: String, n: Int, style: mist.Style) -> String: _ = builder.write_string(lines[i]) if i != len(lines) - 1: - _ = builder.write_string("\n") + _ = builder.write_string(NEWLINE) return str(builder) @@ -702,10 +684,11 @@ struct Style: not mutate the style and instead return a copy. Example: - - var: String = "..." - var user_style = mog.Style().inline(True) - print(user_style.render(user_input)) + ```mojo + var user_input: String = "..." + var user_style = mog.Style().inline(True) + print(user_style.render(user_input)) + ``` Args: value: Value to set the rule to. @@ -952,9 +935,11 @@ struct Style: not mutate the style and instead return a copy. Example: - var: String = "..." - var user_style = mog.Style().max_width(16) - print(user_style.render(user_input)) + ```mojo + var user_input: String = "..." + var user_style = mog.Style().max_width(16) + print(user_style.render(user_input)) + ``` Args: width: The maximum height to apply. @@ -1882,7 +1867,7 @@ struct Style: if fg.isa[NoColor]() and bg.isa[NoColor](): return border - var styler = mist.new_style() + var styler = mist.Style() # Sooooo verbose compared to just passing the string value. But this is closer to the lipgloss API. # It's more verbose because we can't pass around args with trait as the arg type. @@ -1962,7 +1947,6 @@ struct Style: if has_left: if border.left == "": border.left = " " - width += printable_rune_width(border.left) if has_right and border.right == "": @@ -2012,7 +1996,7 @@ struct Style: var top = render_horizontal_edge(border.top_left, border.top, border.top_right, width) top = self.style_border(top, top_fg, top_bg) _ = builder.write_string(top) - _ = builder.write_string("\n") + _ = builder.write_string(NEWLINE) # Render sides var left_runes = List[String]() @@ -2046,13 +2030,13 @@ struct Style: _ = builder.write_string(self.style_border(r, right_fg, right_bg)) if i < len(lines) - 1: - _ = builder.write_string("\n") + _ = builder.write_string(NEWLINE) # Render bottom if has_bottom: var bottom = render_horizontal_edge(border.bottom_left, border.bottom, border.bottom_right, width) bottom = self.style_border(bottom, bottom_fg, bottom_bg) - _ = builder.write_string("\n") + _ = builder.write_string(NEWLINE) _ = builder.write_string(bottom) return str(builder) @@ -2064,7 +2048,7 @@ struct Style: var bottom_margin = self.get_as_int(MARGIN_BOTTOM_KEY) var left_margin = self.get_as_int(MARGIN_LEFT_KEY) - var styler = mist.new_style(self.renderer.color_profile.value) + var styler = mist.Style(self.renderer.color_profile.value) var bgc = self.get_as_color(MARGIN_BACKGROUND_KEY) @@ -2118,7 +2102,7 @@ struct Style: if i != len(texts) - 1: input_text += " " - var term_style = mist.new_style(self.renderer.color_profile.value) + var term_style = mist.Style(self.renderer.color_profile.value) var term_style_space = term_style var term_style_whitespace = term_style @@ -2148,8 +2132,12 @@ struct Style: var max_width = self.get_as_int(MAX_WIDTH_KEY) var max_height = self.get_as_int(MAX_HEIGHT_KEY) - var underline_spaces = underline and self.get_as_bool(UNDERLINE_SPACES_KEY, True) - var crossout_spaces = crossout and self.get_as_bool(CROSSOUT_SPACES_KEY, True) + var underline_spaces = self.get_as_bool(UNDERLINE_SPACES_KEY, False) or ( + underline and self.get_as_bool(UNDERLINE_SPACES_KEY, True) + ) + var crossout_spaces = self.get_as_bool(CROSSOUT_SPACES_KEY, False) or ( + crossout and self.get_as_bool(CROSSOUT_SPACES_KEY, True) + ) # Do we need to style whitespace (padding and space outside paragraphs) separately? var use_whitespace_styler = reverse @@ -2257,7 +2245,7 @@ struct Style: term_style = term_style_space.crossout() if inline: - input_text = input_text.replace("\n", "") + input_text = input_text.replace(NEWLINE, "") # Word wrap if (not inline) and (width > 0): @@ -2268,34 +2256,36 @@ struct Style: input_text = self.maybe_convert_tabs(input_text) var builder = StringBuilder(capacity=int(len(input_text) * 1.5)) - var lines = split(input_text, "\n") + var lines = split_lines(input_text) for i in range(len(lines)): if use_space_styler: # Look for spaces and apply a different styler - for j in range(printable_rune_width(lines[i])): - if lines[i][j] == " ": - _ = builder.write_string(term_style_space.render(lines[i][j])) + for char in lines[i]: + # for j in range(printable_rune_width(lines[i])): + if char == " ": + _ = builder.write_string(term_style_space.render(char)) else: - _ = builder.write_string(term_style.render(lines[i][j])) + _ = builder.write_string(term_style.render(char)) else: _ = builder.write_string(term_style.render(lines[i])) # Readd the newlines if i != len(lines) - 1: - _ = builder.write_string("\n") + _ = builder.write_string(NEWLINE) + var styled_text = str(builder) # Padding if not inline: if left_padding > 0: - var style = mist.new_style(self.renderer.color_profile.value) + var style = mist.Style(self.renderer.color_profile.value) if color_whitespace or use_whitespace_styler: style = term_style_whitespace styled_text = pad_left(styled_text, left_padding, style) if right_padding > 0: - var style = mist.new_style(self.renderer.color_profile.value) + var style = mist.Style(self.renderer.color_profile.value) if color_whitespace or use_whitespace_styler: style = term_style_whitespace styled_text = pad_right(styled_text, right_padding, style) @@ -2312,31 +2302,28 @@ struct Style: # Truncate according to max_width if max_width > 0: - var lines = split(styled_text, "\n") + var lines = split_lines(styled_text) for i in range(len(lines)): lines[i] = truncate(lines[i], max_width) - styled_text = join("\n", lines) + styled_text = join(NEWLINE, lines) # Truncate according to max_height if max_height > 0: - var lines = split(styled_text, "\n") + var lines = split_lines(styled_text) var truncated_lines = lines[0 : min(max_height, len(lines))] - styled_text = join("\n", truncated_lines) + styled_text = join(NEWLINE, truncated_lines) # if transform: # return transform(styled_text) # Apply border at the end - try: - lines = styled_text.split("\n") - except: - lines = List[String](styled_text) + lines = split_lines(styled_text) var number_of_lines = len(lines) if not (number_of_lines == 0 and width == 0): - var style = mist.new_style(self.renderer.color_profile.value) + var style = mist.Style(self.renderer.color_profile.value) if color_whitespace or use_whitespace_styler: style = term_style_whitespace styled_text = align_text_horizontal(styled_text, horizontal_align, width, style) diff --git a/mog/table/__init__.mojo b/src/mog/table/__init__.mojo similarity index 100% rename from mog/table/__init__.mojo rename to src/mog/table/__init__.mojo diff --git a/mog/table/rows.mojo b/src/mog/table/rows.mojo similarity index 100% rename from mog/table/rows.mojo rename to src/mog/table/rows.mojo diff --git a/mog/table/table.mojo b/src/mog/table/table.mojo similarity index 99% rename from mog/table/table.mojo rename to src/mog/table/table.mojo index e19d3ff..4636c7e 100644 --- a/mog/table/table.mojo +++ b/src/mog/table/table.mojo @@ -1,5 +1,5 @@ -from external.weave import truncate_with_tail -from external.gojo.strings import StringBuilder +from weave import truncate_with_tail +from gojo.strings import StringBuilder from ..style import Style from ..border import ROUNDED_BORDER, Border from ..position import top, bottom, left, right, center diff --git a/mog/table/util.mojo b/src/mog/table/util.mojo similarity index 100% rename from mog/table/util.mojo rename to src/mog/table/util.mojo diff --git a/mog/whitespace.mojo b/src/mog/whitespace.mojo similarity index 95% rename from mog/whitespace.mojo rename to src/mog/whitespace.mojo index 60891c7..612ce5e 100644 --- a/mog/whitespace.mojo +++ b/src/mog/whitespace.mojo @@ -1,8 +1,6 @@ -from bit import countl_zero -import external.mist -import external.weave.ansi -from external.gojo.strings import StringBuilder -from external.gojo.unicode import UnicodeString +import mist +import weave.ansi +from gojo.strings import StringBuilder from .renderer import Renderer from .color import ( TerminalColor, @@ -66,9 +64,7 @@ struct WhiteSpace: var i = 0 while i < width: - var uni_str = UnicodeString(self.chars) - - for char in uni_str: + for char in self.chars: _ = b.write_string(char) var printable_width = ansi.printable_rune_width(char) if j >= printable_width: @@ -96,7 +92,7 @@ fn new_whitespace(renderer: Renderer, *opts: WhitespaceOption) -> WhiteSpace: """Creates a new whitespace renderer. The order of the options matters, if you're using WithWhitespaceRenderer, make sure it comes first as other options might depend on it.""" - var w = WhiteSpace(renderer=renderer, style=mist.new_style(renderer.color_profile.value)) + var w = WhiteSpace(renderer=renderer, style=mist.Style(renderer.color_profile.value)) for opt in opts: opt(w) @@ -109,7 +105,7 @@ fn new_whitespace(renderer: Renderer, opts: List[WhitespaceOption]) -> WhiteSpac """Creates a new whitespace renderer. The order of the options matters, if you're using WithWhitespaceRenderer, make sure it comes first as other options might depend on it.""" - var w = WhiteSpace(renderer=renderer, style=mist.new_style(renderer.color_profile.value)) + var w = WhiteSpace(renderer=renderer, style=mist.Style(renderer.color_profile.value)) for opt in opts: opt[](w) diff --git a/src/recipe.yaml b/src/recipe.yaml new file mode 100644 index 0000000..a29ea39 --- /dev/null +++ b/src/recipe.yaml @@ -0,0 +1,50 @@ +# yaml-language-server: $schema=https://raw.githubusercontent.com/prefix-dev/recipe-format/main/schema.json + +context: + version: "13.4.2" + +package: + name: "mog" + version: 0.1.5 + +source: + - path: . + - path: ../LICENSE + - path: ../test + +build: + script: + - mkdir -p ${PREFIX}/lib/mojo + - magic run mojo package mog + - cp mog.mojopkg ${PREFIX}/lib/mojo/mog.mojopkg + +requirements: + run: + - gojo >= 0.1.9,<0.2 + - max >= 24.5.0,<25 + - weave >= 0.1.1,<0.2 + - mist >= 0.1.4,<0.2 + +tests: + - script: + # commands to run to test the package. If any of the commands + # returns with an error code, the test is considered failed. + # if I don't copy everything into a test dir, mojo test runs the tests in the .magic dir and fails :| + - mkdir -p test + - mv test_*.mojo test/ + - mv mog.mojopkg test/ + - magic run mojo test test + + files: + # Extra files to be copied to the test directory from the "work directory" + source: + - mog.mojopkg + - mojoproject.toml + - test_*.mojo + +about: + homepage: https://github.com/thatstoasty/mog + license: MIT + license_file: LICENSE + summary: Style definitions for nice terminal layouts. Built with TUIs in mind. https://github.com/thatstoasty/mog + repository: https://github.com/thatstoasty/mog diff --git a/tests/unit/test_align.mojo b/test/test_align.mojo similarity index 55% rename from tests/unit/test_align.mojo rename to test/test_align.mojo index 8c933ae..00aa73a 100644 --- a/tests/unit/test_align.mojo +++ b/test/test_align.mojo @@ -1,54 +1,46 @@ -from tests.wrapper import MojoTest +import testing from mog.align import align_text_horizontal, align_text_vertical -import external.mist +import mog.mist import mog.position -fn test_align_text_horizontal() raises: - var test = MojoTest("Testing align.align_text_horizontal") - var style = mist.new_style() +def test_align_text_horizontal(): + var style = mist.Style() # Test center alignment var centered = align_text_horizontal("hello", position.center, 10) # print(centered) - test.assert_equal(centered, " hello ") + testing.assert_equal(centered, " hello ") # Test left alignment var left = align_text_horizontal("hello", position.left, 10, style) # print(left) - test.assert_equal(left, "hello ") + testing.assert_equal(left, "hello ") # Test right alignment var right = align_text_horizontal("hello", position.right, 10) # print(right) - test.assert_equal(right, " hello") + testing.assert_equal(right, " hello") -fn test_align_text_vertical() raises: - var test = MojoTest("Testing align.align_text_vertical") - +def test_align_text_vertical(): # Test center alignment var centered = align_text_vertical("hello", position.center, 3) # print(centered) - test.assert_equal(centered, "\nhello\n") + testing.assert_equal(centered, "\nhello\n") # Test top alignment var top = align_text_vertical("hello", position.top, 3) # print(top) - test.assert_equal(top, "hello\n\n") + testing.assert_equal(top, "hello\n\n") # Test bottom alignment var bottom = align_text_vertical("hello", position.bottom, 5) # print(bottom) - test.assert_equal(bottom, "\n\n\n\nhello") - - -fn main() raises: - test_align_text_horizontal() - test_align_text_vertical() + testing.assert_equal(bottom, "\n\n\n\nhello") diff --git a/tests/unit/test_join.mojo b/test/test_join.mojo similarity index 82% rename from tests/unit/test_join.mojo rename to test/test_join.mojo index 9b732d6..c5f1547 100644 --- a/tests/unit/test_join.mojo +++ b/test/test_join.mojo @@ -1,10 +1,9 @@ -from tests.wrapper import MojoTest +import testing from mog.join import join_horizontal, join_vertical import mog.position -fn test_horizontal_join() raises: - var test = MojoTest("Testing join.horizontal_join") +def test_horizontal_join(): var a = "Hello World!\nThis is an example." var b = "I could be more creative.\nBut, I'm out of ideas." @@ -12,7 +11,7 @@ fn test_horizontal_join() raises: var bottom_aligned = join_horizontal(position.bottom, a, b) # print(bottom_aligned) - test.assert_equal( + testing.assert_equal( bottom_aligned, "Hello World! I could be more creative.\nThis is an example.But, I'm out of ideas. ", ) @@ -20,7 +19,7 @@ fn test_horizontal_join() raises: var top_aligned = join_horizontal(position.top, a, b) # print(top_aligned) - test.assert_equal( + testing.assert_equal( top_aligned, "Hello World! I could be more creative.\nThis is an example.But, I'm out of ideas. ", ) @@ -28,21 +27,20 @@ fn test_horizontal_join() raises: var center_aligned = join_horizontal(position.center, a, b) # print(center_aligned) - test.assert_equal( + testing.assert_equal( center_aligned, "Hello World! I could be more creative.\nThis is an example.But, I'm out of ideas. ", ) -fn test_vertical_join() raises: - var test = MojoTest("Testing join.vertical_join") +def test_vertical_join(): var a = "Hello World!\nThis is an example." var b = "I could be more creative.\nBut, I'm out of ideas." # Test vertically joining two paragraphs along their right border var right_aligned = join_vertical(position.right, a, b) # print(right_aligned) - test.assert_equal( + testing.assert_equal( right_aligned, " Hello World!\n This is an example.\nI could be more creative.\n But, I'm out of ideas.", ) @@ -50,7 +48,7 @@ fn test_vertical_join() raises: # Test vertically joining two paragraphs along their left border var left_aligned = join_vertical(position.left, a, b) # print(left_aligned) - test.assert_equal( + testing.assert_equal( left_aligned, "Hello World! \nThis is an example. \nI could be more creative.\nBut, I'm out of ideas. ", ) @@ -58,12 +56,7 @@ fn test_vertical_join() raises: # Test vertically joining two paragraphs along their center axis var center_aligned = join_vertical(position.center, a, b) # print(center_aligned) - test.assert_equal( + testing.assert_equal( center_aligned, " Hello World! \n This is an example. \nI could be more creative.\n But, I'm out of ideas. ", ) - - -fn main() raises: - test_horizontal_join() - test_vertical_join() diff --git a/tests/integration/test_mog.mojo b/test/test_mog.mojo similarity index 90% rename from tests/integration/test_mog.mojo rename to test/test_mog.mojo index 7f0b6c9..dac284d 100644 --- a/tests/integration/test_mog.mojo +++ b/test/test_mog.mojo @@ -1,4 +1,3 @@ -from tests.wrapper import MojoTest from mog.join import join_vertical, join_horizontal from mog.table import new_table, Table, StringData from mog.table.table import default_styles @@ -27,8 +26,7 @@ fn dummy_style_func(row: Int, col: Int) -> Style: return style -fn test_table() raises: - var test = MojoTest("Testing table creation with and without headers") +def test_table(): var border_style = mog.Style().foreground(mog.Color(0x39E506)) var table = Table( @@ -68,8 +66,7 @@ fn test_table() raises: ) -fn test_horizontal_joined_paragraphs() raises: - var test = MojoTest("Testing Style rendering") +def test_horizontal_joined_paragraphs(): var style_build_start = now() var style = mog.Style().bold().width(50).padding(1, 1, 1, 1).horizontal_alignment(position.center).border( ROUNDED_BORDER @@ -128,7 +125,7 @@ fn test_horizontal_joined_paragraphs() raises: print("Block execution time: ", execution_time, execution_time / 1e9) -fn test_borderless_paragraph() raises: +def test_borderless_paragraph(): var borderless_style = mog.Style().width(50).padding(1, 2).horizontal_alignment(position.center).border( HIDDEN_BORDER ).background(mog.Color(0xC9A0DC)) @@ -148,12 +145,3 @@ fn test_borderless_paragraph() raises: ), ) ) - - -fn main() raises: - var start_test = now() - test_horizontal_joined_paragraphs() - var test_duration = now() - start_test - print("Test duration: ", test_duration, test_duration / 1e9) - test_borderless_paragraph() - test_table() diff --git a/test/test_render.mojo b/test/test_render.mojo new file mode 100644 index 0000000..515fd76 --- /dev/null +++ b/test/test_render.mojo @@ -0,0 +1,15 @@ +import testing +import mog + + +def test_unicode_handling(): + alias a: String = "Hello──World!" + print( + mog.Style() + .faint() + .border(mog.ROUNDED_BORDER) + .render(mog.Style().border(mog.ROUNDED_BORDER).underline().foreground(mog.Color(0xFAFAFA)).render(a)) + ) + # print(mog.Style().border(mog.ROUNDED_BORDER).underline().foreground(mog.Color(0xFAFAFA)).render(a).split("\n").__str__()) + + # testing.assert_equal(mog.Style().border(mog.ROUNDED_BORDER).underline().foreground(mog.Color(0xFAFAFA)).render(a), "\x1B[;94mHello──World!\x1B[0m") diff --git a/test/test_size.mojo b/test/test_size.mojo new file mode 100644 index 0000000..5f65961 --- /dev/null +++ b/test/test_size.mojo @@ -0,0 +1,21 @@ +import testing +from mog.size import get_height, get_width, get_size + + +def test_get_height(): + var text = "This\nis\na\ntest\nstring" + testing.assert_equal(get_height(text), 5) + + +def test_get_width(): + var text = "This\nis\na\ntest\nstring" + testing.assert_equal(get_width(text), 6) + + +def test_get_size(): + var text = "This\nis\na\ntest\nstring" + var height: Int + var width: Int + width, height = get_size(text) + testing.assert_equal(width, 6) + testing.assert_equal(height, 5) diff --git a/tests/__init__.mojo b/tests/__init__.mojo deleted file mode 100644 index e69de29..0000000 diff --git a/tests/integration/__init__.mojo b/tests/integration/__init__.mojo deleted file mode 100644 index e69de29..0000000 diff --git a/tests/unit/__init__.mojo b/tests/unit/__init__.mojo deleted file mode 100644 index e69de29..0000000 diff --git a/tests/unit/test_size.mojo b/tests/unit/test_size.mojo deleted file mode 100644 index f555a7f..0000000 --- a/tests/unit/test_size.mojo +++ /dev/null @@ -1,30 +0,0 @@ -from tests.wrapper import MojoTest -from mog.size import get_height, get_width, get_size - - -fn test_get_height() raises: - var test = MojoTest("Testing size.get_height") - var text = "This\nis\na\ntest\nstring" - test.assert_equal(get_height(text), 5) - - -fn test_get_width() raises: - var test = MojoTest("Testing size.get_width") - var text = "This\nis\na\ntest\nstring" - test.assert_equal(get_width(text), 6) - - -fn test_get_size() raises: - var test = MojoTest("Testing size.get_size") - var text = "This\nis\na\ntest\nstring" - var height: Int - var width: Int - width, height = get_size(text) - test.assert_equal(width, 6) - test.assert_equal(height, 5) - - -fn main() raises: - test_get_height() - test_get_width() - test_get_size() diff --git a/tests/wrapper.mojo b/tests/wrapper.mojo deleted file mode 100644 index bdf3f87..0000000 --- a/tests/wrapper.mojo +++ /dev/null @@ -1,38 +0,0 @@ -from testing import testing - - -@value -struct MojoTest: - """ - A utility struct for testing. - """ - - var test_name: String - - fn __init__(inout self, test_name: String): - self.test_name = test_name - print("# " + test_name) - - fn assert_true(self, cond: Bool, message: String = ""): - try: - if message == "": - testing.assert_true(cond) - else: - testing.assert_true(cond, message) - except e: - print(e) - - fn assert_false(self, cond: Bool, message: String = ""): - try: - if message == "": - testing.assert_false(cond) - else: - testing.assert_false(cond, message) - except e: - print(e) - - fn assert_equal[T: testing.Testable](self, left: T, right: T): - try: - testing.assert_equal(left, right) - except e: - print(e)