diff --git a/.check.exs b/.check.exs new file mode 100644 index 0000000..e8a3888 --- /dev/null +++ b/.check.exs @@ -0,0 +1,13 @@ +[ + fix: true, + tools: [ + {:sobelow, false}, + {:gettext, false}, + {:mix_audit, false}, + {:hex_audit, "mix hex.audit"}, + {:scenic_renderer_test, "cd native/scenic_renderer ; cargo test"}, + {:scenic_renderer_clippy, "cd native/scenic_renderer ; cargo clippy"}, + {:scenic_window_test, "cd native/scenic_window ; cargo test"}, + {:scenic_window_clippy, "cd native/scenic_window ; cargo clippy"} + ] +] diff --git a/.credo.exs b/.credo.exs new file mode 100644 index 0000000..3199bf2 --- /dev/null +++ b/.credo.exs @@ -0,0 +1,212 @@ +# This file contains the configuration for Credo and you are probably reading +# this after creating it with `mix credo.gen.config`. +# +# If you find anything wrong or unclear in this file, please report an +# issue on GitHub: https://github.com/rrrene/credo/issues +# +%{ + # + # You can have as many configs as you like in the `configs:` field. + configs: [ + %{ + # + # Run any config using `mix credo -C `. If no config name is given + # "default" is used. + # + name: "default", + # + # These are the files included in the analysis: + files: %{ + # + # You can give explicit globs or simply directories. + # In the latter case `**/*.{ex,exs}` will be used. + # + included: [ + "lib/", + "src/", + "test/", + ], + excluded: [~r"/_build/", ~r"/deps/", ~r"/node_modules/", "test/support/"] + }, + # + # Load and configure plugins here: + # + plugins: [], + # + # If you create your own checks, you must specify the source files for + # them here, so they can be loaded by Credo before running the analysis. + # + requires: [], + # + # If you want to enforce a style guide and need a more traditional linting + # experience, you can change `strict` to `true` below: + # + strict: false, + # + # To modify the timeout for parsing files, change this value: + # + parse_timeout: 5000, + # + # If you want to use uncolored output by default, you can change `color` + # to `false` below: + # + color: true, + # + # You can customize the parameters of any check by adding a second element + # to the tuple. + # + # To disable a check put `false` as second element: + # + # {Credo.Check.Design.DuplicatedCode, false} + # + checks: %{ + enabled: [ + # + ## Consistency Checks + # + {Credo.Check.Consistency.ExceptionNames, []}, + {Credo.Check.Consistency.LineEndings, []}, + {Credo.Check.Consistency.ParameterPatternMatching, []}, + {Credo.Check.Consistency.SpaceAroundOperators, []}, + {Credo.Check.Consistency.SpaceInParentheses, []}, + {Credo.Check.Consistency.TabsOrSpaces, []}, + + # + ## Design Checks + # + # You can customize the priority of any check + # Priority values are: `low, normal, high, higher` + # + {Credo.Check.Design.AliasUsage, + [priority: :low, if_nested_deeper_than: 2, if_called_more_often_than: 0]}, + {Credo.Check.Design.TagFIXME, []}, + # You can also customize the exit_status of each check. + # If you don't want TODO comments to cause `mix credo` to fail, just + # set this value to 0 (zero). + # + {Credo.Check.Design.TagTODO, [exit_status: 2]}, + + # + ## Readability Checks + # + {Credo.Check.Readability.AliasOrder, []}, + {Credo.Check.Readability.FunctionNames, []}, + {Credo.Check.Readability.LargeNumbers, []}, + {Credo.Check.Readability.MaxLineLength, [priority: :low, max_length: 120]}, + {Credo.Check.Readability.ModuleAttributeNames, []}, + {Credo.Check.Readability.ModuleDoc, []}, + {Credo.Check.Readability.ModuleNames, []}, + {Credo.Check.Readability.ParenthesesInCondition, []}, + {Credo.Check.Readability.ParenthesesOnZeroArityDefs, []}, + {Credo.Check.Readability.PipeIntoAnonymousFunctions, []}, + {Credo.Check.Readability.PredicateFunctionNames, []}, + {Credo.Check.Readability.PreferImplicitTry, []}, + {Credo.Check.Readability.RedundantBlankLines, []}, + {Credo.Check.Readability.Semicolons, []}, + {Credo.Check.Readability.SpaceAfterCommas, []}, + {Credo.Check.Readability.StringSigils, []}, + {Credo.Check.Readability.TrailingBlankLine, []}, + {Credo.Check.Readability.TrailingWhiteSpace, []}, + {Credo.Check.Readability.UnnecessaryAliasExpansion, []}, + {Credo.Check.Readability.VariableNames, []}, + {Credo.Check.Readability.WithSingleClause, []}, + + # + ## Refactoring Opportunities + # + {Credo.Check.Refactor.Apply, []}, + {Credo.Check.Refactor.CondStatements, []}, + {Credo.Check.Refactor.CyclomaticComplexity, []}, + {Credo.Check.Refactor.FilterCount, []}, + {Credo.Check.Refactor.FilterFilter, []}, + {Credo.Check.Refactor.FunctionArity, []}, + {Credo.Check.Refactor.LongQuoteBlocks, []}, + {Credo.Check.Refactor.MapJoin, []}, + {Credo.Check.Refactor.MatchInCondition, []}, + {Credo.Check.Refactor.NegatedConditionsInUnless, []}, + {Credo.Check.Refactor.NegatedConditionsWithElse, []}, + {Credo.Check.Refactor.Nesting, []}, + {Credo.Check.Refactor.RedundantWithClauseResult, []}, + {Credo.Check.Refactor.RejectReject, []}, + {Credo.Check.Refactor.UnlessWithElse, []}, + {Credo.Check.Refactor.WithClauses, []}, + + # + ## Warnings + # + {Credo.Check.Warning.ApplicationConfigInModuleAttribute, []}, + {Credo.Check.Warning.BoolOperationOnSameValues, []}, + {Credo.Check.Warning.Dbg, []}, + {Credo.Check.Warning.ExpensiveEmptyEnumCheck, []}, + {Credo.Check.Warning.IExPry, []}, + {Credo.Check.Warning.IoInspect, []}, + {Credo.Check.Warning.MissedMetadataKeyInLoggerConfig, []}, + {Credo.Check.Warning.OperationOnSameValues, []}, + {Credo.Check.Warning.OperationWithConstantResult, []}, + {Credo.Check.Warning.RaiseInsideRescue, []}, + {Credo.Check.Warning.SpecWithStruct, []}, + {Credo.Check.Warning.UnsafeExec, []}, + {Credo.Check.Warning.UnusedEnumOperation, []}, + {Credo.Check.Warning.UnusedFileOperation, []}, + {Credo.Check.Warning.UnusedKeywordOperation, []}, + {Credo.Check.Warning.UnusedListOperation, []}, + {Credo.Check.Warning.UnusedPathOperation, []}, + {Credo.Check.Warning.UnusedRegexOperation, []}, + {Credo.Check.Warning.UnusedStringOperation, []}, + {Credo.Check.Warning.UnusedTupleOperation, []}, + {Credo.Check.Warning.WrongTestFileExtension, []} + ], + disabled: [ + # + # Checks scheduled for next check update (opt-in for now) + {Credo.Check.Refactor.UtcNowTruncate, []}, + + # + # Controversial and experimental checks (opt-in, just move the check to `:enabled` + # and be sure to use `mix credo --strict` to see low priority checks) + # + {Credo.Check.Consistency.MultiAliasImportRequireUse, []}, + {Credo.Check.Consistency.UnusedVariableNames, []}, + {Credo.Check.Design.DuplicatedCode, []}, + {Credo.Check.Design.SkipTestWithoutComment, []}, + {Credo.Check.Readability.AliasAs, []}, + {Credo.Check.Readability.BlockPipe, []}, + {Credo.Check.Readability.ImplTrue, []}, + {Credo.Check.Readability.MultiAlias, []}, + {Credo.Check.Readability.NestedFunctionCalls, []}, + {Credo.Check.Readability.OneArityFunctionInPipe, []}, + {Credo.Check.Readability.OnePipePerLine, []}, + {Credo.Check.Readability.SeparateAliasRequire, []}, + {Credo.Check.Readability.SingleFunctionToBlockPipe, []}, + {Credo.Check.Readability.SinglePipe, []}, + {Credo.Check.Readability.Specs, []}, + {Credo.Check.Readability.StrictModuleLayout, []}, + {Credo.Check.Readability.WithCustomTaggedTuple, []}, + {Credo.Check.Refactor.ABCSize, []}, + {Credo.Check.Refactor.AppendSingleItem, []}, + {Credo.Check.Refactor.DoubleBooleanNegation, []}, + {Credo.Check.Refactor.FilterReject, []}, + {Credo.Check.Refactor.IoPuts, []}, + {Credo.Check.Refactor.MapMap, []}, + {Credo.Check.Refactor.ModuleDependencies, []}, + {Credo.Check.Refactor.NegatedIsNil, []}, + {Credo.Check.Refactor.PassAsyncInTestCases, []}, + {Credo.Check.Refactor.PipeChainStart, []}, + {Credo.Check.Refactor.RejectFilter, []}, + {Credo.Check.Refactor.VariableRebinding, []}, + {Credo.Check.Warning.LazyLogging, []}, + {Credo.Check.Warning.LeakyEnvironment, []}, + {Credo.Check.Warning.MapGetUnsafePass, []}, + {Credo.Check.Warning.MixEnv, []}, + {Credo.Check.Warning.UnsafeToAtom, []} + + # {Credo.Check.Refactor.MapInto, []}, + + # + # Custom checks can be created using `mix credo.gen.check`. + # + ] + } + } + ] +} diff --git a/.doctor.exs b/.doctor.exs new file mode 100644 index 0000000..f335f04 --- /dev/null +++ b/.doctor.exs @@ -0,0 +1,16 @@ +%Doctor.Config{ + ignore_modules: [ + ~r/^Example/, + ], + ignore_paths: [], + min_module_doc_coverage: 40, + min_module_spec_coverage: 0, + min_overall_doc_coverage: 50, + min_overall_spec_coverage: 0, + min_overall_moduledoc_coverage: 100, + exception_moduledoc_required: true, + raise: false, + reporter: Doctor.Reporters.Full, + struct_type_spec_required: true, + umbrella: false +} diff --git a/.drone.yml b/.drone.yml new file mode 100644 index 0000000..5cab269 --- /dev/null +++ b/.drone.yml @@ -0,0 +1,415 @@ +kind: pipeline +type: docker +name: build + +steps: + - name: restore ASDF cache + image: meltwater/drone-cache + pull: "always" + environment: + AWS_ACCESS_KEY_ID: + from_secret: ACCESS_KEY_ID + AWS_SECRET_ACCESS_KEY: + from_secret: SECRET_ACCESS_KEY + AWS_PLUGIN_PATH_STYLE: true + settings: + restore: true + endpoint: + from_secret: S3_ENDPOINT + bucket: + from_secret: CACHE_BUCKET + region: us-east-1 + path-style: true + cache_key: 'asdf-{{ os }}-{{ arch }}-{{ checksum ".tool-versions" }}' + mount: + - .asdf + + - name: restore build cache + image: meltwater/drone-cache + environment: + AWS_ACCESS_KEY_ID: + from_secret: ACCESS_KEY_ID + AWS_SECRET_ACCESS_KEY: + from_secret: SECRET_ACCESS_KEY + AWS_PLUGIN_PATH_STYLE: true + settings: + restore: true + endpoint: + from_secret: S3_ENDPOINT + bucket: + from_secret: CACHE_BUCKET + region: us-east-1 + path-style: true + cache_key: 'elixir-{{ checksum "mix.lock" }}-{{ checksum ".tool-versions" }}' + mount: + - deps + - _build + - .hex + - .mix + - .rebar3 + - native/scenic_window/target + - native/scenic_renderer/target + + - name: install dependencies + image: harton.dev/james/asdf_container:latest + pull: "always" + environment: + MIX_ENV: test + HEX_HOME: /drone/src/.hex + MIX_HOME: /drone/src/.mix + REBAR_BASE_DIR: /drone/src/.rebar3 + ASDF_DATA_DIR: /drone/src/.asdf + ASDF_DIR: /root/.asdf + depends_on: + - restore ASDF cache + - restore build cache + commands: + - asdf_install + - rm -rf .asdf/downloads + - . $ASDF_DIR/asdf.sh + - mix local.hex --if-missing --force + - mix local.rebar --if-missing --force + - mix deps.get + - mix deps.compile + - mix dialyzer --plt + + - name: store ASDF cache + image: meltwater/drone-cache + environment: + AWS_ACCESS_KEY_ID: + from_secret: ACCESS_KEY_ID + AWS_SECRET_ACCESS_KEY: + from_secret: SECRET_ACCESS_KEY + AWS_PLUGIN_PATH_STYLE: true + depends_on: + - install dependencies + settings: + rebuild: true + override: false + endpoint: + from_secret: S3_ENDPOINT + bucket: + from_secret: CACHE_BUCKET + region: us-east-1 + path-style: true + cache_key: 'asdf-{{ os }}-{{ arch }}-{{ checksum ".tool-versions" }}' + mount: + - .asdf + + - name: store build cache + image: meltwater/drone-cache + environment: + AWS_ACCESS_KEY_ID: + from_secret: ACCESS_KEY_ID + AWS_SECRET_ACCESS_KEY: + from_secret: SECRET_ACCESS_KEY + AWS_PLUGIN_PATH_STYLE: true + depends_on: + - install dependencies + settings: + rebuild: true + override: false + endpoint: + from_secret: S3_ENDPOINT + bucket: + from_secret: CACHE_BUCKET + region: us-east-1 + path-style: true + cache_key: 'elixir-{{ checksum "mix.lock" }}-{{ checksum ".tool-versions" }}' + mount: + - deps + - _build + - .hex + - .mix + - .rebar3 + - native/scenic_window/target + - native/scenic_renderer/target + + - name: mix compile + image: harton.dev/james/asdf_container:latest + environment: + MIX_ENV: test + HEX_HOME: /drone/src/.hex + MIX_HOME: /drone/src/.mix + REBAR_BASE_DIR: /drone/src/.rebar3 + ASDF_DATA_DIR: /drone/src/.asdf + depends_on: + - install dependencies + commands: + - asdf mix compile --warnings-as-errors + + - name: mix test + image: harton.dev/james/asdf_container:latest + environment: + MIX_ENV: test + HEX_HOME: /drone/src/.hex + MIX_HOME: /drone/src/.mix + REBAR_BASE_DIR: /drone/src/.rebar3 + ASDF_DATA_DIR: /drone/src/.asdf + depends_on: + - mix compile + commands: + - asdf mix test + + - name: mix credo + image: harton.dev/james/asdf_container:latest + environment: + MIX_ENV: test + HEX_HOME: /drone/src/.hex + MIX_HOME: /drone/src/.mix + REBAR_BASE_DIR: /drone/src/.rebar3 + ASDF_DATA_DIR: /drone/src/.asdf + depends_on: + - mix compile + commands: + - asdf mix credo --strict + + - name: mix hex.audit + image: harton.dev/james/asdf_container:latest + environment: + MIX_ENV: test + HEX_HOME: /drone/src/.hex + MIX_HOME: /drone/src/.mix + REBAR_BASE_DIR: /drone/src/.rebar3 + ASDF_DATA_DIR: /drone/src/.asdf + depends_on: + - mix compile + commands: + - asdf mix hex.audit + + - name: mix format + image: harton.dev/james/asdf_container:latest + environment: + MIX_ENV: test + HEX_HOME: /drone/src/.hex + MIX_HOME: /drone/src/.mix + REBAR_BASE_DIR: /drone/src/.rebar3 + ASDF_DATA_DIR: /drone/src/.asdf + depends_on: + - mix compile + commands: + - asdf mix format --check-formatted + + - name: mix deps.unlock + image: harton.dev/james/asdf_container:latest + environment: + MIX_ENV: test + HEX_HOME: /drone/src/.hex + MIX_HOME: /drone/src/.mix + REBAR_BASE_DIR: /drone/src/.rebar3 + ASDF_DATA_DIR: /drone/src/.asdf + depends_on: + - mix compile + commands: + - asdf mix deps.unlock --check-unused + + - name: mix doctor + image: harton.dev/james/asdf_container:latest + environment: + MIX_ENV: test + HEX_HOME: /drone/src/.hex + MIX_HOME: /drone/src/.mix + REBAR_BASE_DIR: /drone/src/.rebar3 + ASDF_DATA_DIR: /drone/src/.asdf + depends_on: + - mix compile + commands: + - asdf mix doctor --full + + - name: cargo test scenic_renderer + image: harton.dev/james/asdf_container:latest + environment: + ASDF_DATA_DIR: /drone/src/.asdf + depends_on: + - install dependencies + commands: + - (cd native/scenic_renderer && cargo test) + + - name: cargo clippy scenic_renderer + image: harton.dev/james/asdf_container:latest + environment: + ASDF_DATA_DIR: /drone/src/.asdf + depends_on: + - install dependencies + commands: + - (cd native/scenic_renderer && cargo clippy) + + - name: cargo test scenic_window + image: harton.dev/james/asdf_container:latest + environment: + ASDF_DATA_DIR: /drone/src/.asdf + depends_on: + - install dependencies + commands: + - (cd native/scenic_window && cargo test) + + - name: cargo clippy scenic_window + image: harton.dev/james/asdf_container:latest + environment: + ASDF_DATA_DIR: /drone/src/.asdf + depends_on: + - install dependencies + commands: + - (cd native/scenic_window && cargo clippy) + + - name: mix git_ops.check_message + image: harton.dev/james/asdf_container:latest + environment: + MIX_ENV: test + HEX_HOME: /drone/src/.hex + MIX_HOME: /drone/src/.mix + REBAR_BASE_DIR: /drone/src/.rebar3 + ASDF_DATA_DIR: /drone/src/.asdf + depends_on: + - mix compile + commands: + - git log -1 --format=%s > .last_commit_message + - asdf mix git_ops.check_message .last_commit_message + + - name: mix git_ops.release + image: harton.dev/james/asdf_container:latest + when: + branch: + - main + event: + exclude: + - pull_request + depends_on: + - mix test + - mix credo + - mix hex.audit + - mix format + - mix deps.unlock + - mix doctor + - mix git_ops.check_message + - cargo test scenic_window + - cargo clippy scenic_window + - cargo test scenic_renderer + - cargo clippy scenic_renderer + environment: + MIX_ENV: test + HEX_HOME: /drone/src/.hex + MIX_HOME: /drone/src/.mix + REBAR_BASE_DIR: /drone/src/.rebar3 + ASDF_DATA_DIR: /drone/src/.asdf + ASDF_DIR: /root/.asdf + DRONE_TOKEN: + from_secret: DRONE_TOKEN + commands: + - git fetch --tags + - . $ASDF_DIR/asdf.sh + - mix git_ops.project_info --format=shell > before.env + - mix git_ops.release --yes --no-major || true + - mix git_ops.project_info --format=shell > after.env + - . ./before.env + - export OLD_APP_VERSION=$${APP_VERSION} + - . ./after.env + - export NEW_APP_VERSION=$${APP_VERSION} + - if [ "v$${OLD_APP_VERSION}" != "v$${NEW_APP_VERSION}" ]; then + - export GIT_URL=$(echo $DRONE_GIT_HTTP_URL | sed -e "s/:\\/\\//:\\/\\/$DRONE_REPO_OWNER:$DRONE_TOKEN@/") + - git push $${GIT_URL} "HEAD:${DRONE_COMMIT_REF}" "refs/tags/v$${NEW_APP_VERSION}" + - fi + + - name: build artifacts + image: harton.dev/james/asdf_container:latest + when: + event: + - tag + refs: + include: + - refs/tags/v* + depends_on: + - mix test + - mix credo + - mix hex.audit + - mix format + - mix deps.unlock + - mix doctor + - mix git_ops.check_message + - cargo test scenic_window + - cargo clippy scenic_window + - cargo test scenic_renderer + - cargo clippy scenic_renderer + environment: + MIX_ENV: test + HEX_HOME: /drone/src/.hex + MIX_HOME: /drone/src/.mix + REBAR_BASE_DIR: /drone/src/.rebar3 + ASDF_DATA_DIR: /drone/src/.asdf + ASDF_DIR: /root/.asdf + commands: + - . $ASDF_DIR/asdf.sh + - mix git_ops.project_info --format=shell > app.env + - . ./app.env + - mkdir artifacts + - mix hex.build -o "artifacts/$${APP_NAME}-$${APP_VERSION}-pkg.tar" + - gzip "artifacts/$${APP_NAME}-$${APP_VERSION}-pkg.tar" + - mix docs + - tar zcvf "artifacts/$${APP_NAME}-$${APP_VERSION}-docs.tar.gz" doc/ + - git tag -l --format='%(contents:subject)' v$${APP_VERSION} > tag_subject + - git tag -l --format='%(contents:body)' v$${APP_VERSION} > tag_body + + - name: gitea release + image: plugins/gitea-release + when: + event: + - tag + refs: + include: + - refs/tags/v* + depends_on: + - build artifacts + settings: + api_key: + from_secret: DRONE_TOKEN + base_url: https://harton.dev + files: artifacts/*.tar.gz + checksum: sha256 + title: tag_subject + note: tag_body + + - name: docs release + when: + event: + - tag + refs: + include: + - refs/tags/v* + image: minio/mc + environment: + S3_ENDPOINT: + from_secret: S3_ENDPOINT + ACCESS_KEY: + from_secret: ACCESS_KEY_ID + SECRET_KEY: + from_secret: SECRET_ACCESS_KEY + depends_on: + - build artifacts + commands: + - mc alias set store $${S3_ENDPOINT} $${ACCESS_KEY} $${SECRET_KEY} + - mc mb -p store/docs.harton.nz + - mc mirror --overwrite doc/ store/docs.harton.nz/$${DRONE_REPO}/$${DRONE_TAG} + - mc mirror --overwrite doc/ store/docs.harton.nz/$${DRONE_REPO} + + # - name: hex release + # image: harton.dev/james/asdf_container:latest + # when: + # event: + # - tag + # refs: + # include: + # - refs/tags/v* + # depends_on: + # - build artifacts + # environment: + # MIX_ENV: test + # HEX_HOME: /drone/src/.hex + # MIX_HOME: /drone/src/.mix + # REBAR_BASE_DIR: /drone/src/.rebar3 + # ASDF_DATA_DIR: /drone/src/.asdf + # ASDF_DIR: /root/.asdf + # HEX_API_KEY: + # from_secret: HEX_API_KEY + # commands: + # - . $ASDF_DIR/asdf.sh + # - mix hex.publish --yes diff --git a/config/config.exs b/config/config.exs index 28b7e07..77aeb0f 100644 --- a/config/config.exs +++ b/config/config.exs @@ -13,3 +13,11 @@ if Mix.env() in [:dev, :test] do config :scenic, :assets, module: ExampleAssets end + +config :git_ops, + mix_project: Mix.Project.get!(), + changelog_file: "CHANGELOG.md", + repository_url: "https://harton.dev/james/scenic_driver_renderling", + manage_mix_version?: true, + manage_readme_version: "README.md", + version_tag_prefix: "v" diff --git a/lib/scenic_driver_rendering/window/config.ex b/lib/scenic_driver_rendering/window/config.ex index 1d1a6e0..c13a4c0 100644 --- a/lib/scenic_driver_rendering/window/config.ex +++ b/lib/scenic_driver_rendering/window/config.ex @@ -1,4 +1,12 @@ defmodule Scenic.Driver.Renderling.Window.Config do + @moduledoc """ + Configuration generated by parsing the options provided to the driver. + + It's a struct to make it easier to derive from rustler. + """ + + alias __MODULE__.{Position, Window} + defstruct name: nil, antialias: true, position: nil, @@ -9,30 +17,6 @@ defmodule Scenic.Driver.Renderling.Window.Config do input_blacklist: [], server_path: nil - defmodule Position do - defstruct scaled: false, centered: false, orientation: :normal - - @type t :: %__MODULE__{ - scaled: boolean, - centered: boolean, - orientation: :normal | :left | :right | :upside_down - } - - def init(opts), do: struct(__MODULE__, opts) - end - - defmodule Window do - defstruct title: "Scenic Window", resizeable: false, width: nil, height: nil - - @type t :: %__MODULE__{ - title: String.t(), - resizeable: false, - width: nil | non_neg_integer(), - height: nil | non_neg_integer() - } - def init(opts), do: struct(__MODULE__, opts) - end - @type t :: %__MODULE__{ name: atom | String.t(), antialias: boolean, @@ -45,6 +29,8 @@ defmodule Scenic.Driver.Renderling.Window.Config do server_path: Path.t() } + @doc false + @spec init(keyword) :: t def init(opts) do attrs = opts diff --git a/lib/scenic_driver_rendering/window/config/position.ex b/lib/scenic_driver_rendering/window/config/position.ex new file mode 100644 index 0000000..42a9475 --- /dev/null +++ b/lib/scenic_driver_rendering/window/config/position.ex @@ -0,0 +1,25 @@ +defmodule Scenic.Driver.Renderling.Window.Config.Position do + @moduledoc """ + Configuration generated by parsing the options provided to the driver. + + It's a struct to make it easier to derive from rustler. + """ + + defstruct scaled: false, + centered: false, + orientation: :normal, + maximised: false, + full_screen: false + + @type t :: %__MODULE__{ + scaled: boolean, + centered: boolean, + orientation: :normal | :left | :right | :upside_down, + maximised: boolean, + full_screen: boolean + } + + @doc false + @spec init(keyword) :: t + def init(opts), do: struct(__MODULE__, opts) +end diff --git a/lib/scenic_driver_rendering/window/config/window.ex b/lib/scenic_driver_rendering/window/config/window.ex new file mode 100644 index 0000000..5cf7338 --- /dev/null +++ b/lib/scenic_driver_rendering/window/config/window.ex @@ -0,0 +1,20 @@ +defmodule Scenic.Driver.Renderling.Window.Config.Window do + @moduledoc """ + Configuration generated by parsing the options provided to the driver. + + It's a struct to make it easier to derive from rustler. + """ + + defstruct title: "Scenic Window", resizeable: false, width: nil, height: nil + + @type t :: %__MODULE__{ + title: String.t(), + resizeable: false, + width: nil | non_neg_integer(), + height: nil | non_neg_integer() + } + + @doc false + @spec init(keyword) :: t + def init(opts), do: struct(__MODULE__, opts) +end diff --git a/lib/scenic_driver_rendering/window/nif.ex b/lib/scenic_driver_rendering/window/nif.ex index 0523a33..22c4aeb 100644 --- a/lib/scenic_driver_rendering/window/nif.ex +++ b/lib/scenic_driver_rendering/window/nif.ex @@ -1,11 +1,54 @@ defmodule Scenic.Driver.Renderling.Window.Nif do + @moduledoc """ + Provides the NIF interface to the `scenic_window` crate. + """ + use Rustler, otp_app: :scenic_driver_renderling, crate: :scenic_window + alias Scenic.{Color, Driver.Renderling.Window.Config, Script, ViewPort.Input} + + @doc """ + Initialise a new window server. + + The returned reference refers to the server structure in the `scenic_window` + crate. If this reference is GC'd then the server will be torn down. + """ + @spec init(Config.t()) :: reference() def init(_config), do: :erlang.nif_error(:nif_not_loaded) + + @doc """ + Send an update-scene event to the server. + """ + @spec update_scene(Script.t(), Script.id(), reference) :: :ok def update_scene(_script, _script_id, _resource), do: :erlang.nif_error(:nif_not_loaded) + + @doc """ + Tell the server to reset the scene. + """ + @spec reset_scene(reference) :: :ok def reset_scene(_resource), do: :erlang.nif_error(:nif_not_loaded) + + @doc """ + Remove the named scripts from the scene. + """ + @spec del_scripts([Script.id()], reference) :: :ok def del_scripts(_script_ids, _resource), do: :erlang.nif_error(:nif_not_loaded) + + @doc """ + Changes the background color of the scene. + """ + @spec clear_color(Color.t(), reference) :: :ok def clear_color(_color, _resource), do: :erlang.nif_error(:nif_not_loaded) + + @doc """ + Tell the server that it's no longer needed. + """ + @spec terminate(reference) :: :ok def terminate(_resource), do: :erlang.nif_error(:nif_not_loaded) + + @doc """ + Tell the server to filter the input events to the named classes. + """ + @spec request_input(Input.class(), reference) :: :ok def request_input(_input_classes, _resource), do: :erlang.nif_error(:nif_not_loaded) end diff --git a/lib/scenic_driver_rendering/window/window.ex b/lib/scenic_driver_rendering/window/window.ex index f10e1ed..b00821a 100644 --- a/lib/scenic_driver_rendering/window/window.ex +++ b/lib/scenic_driver_rendering/window/window.ex @@ -137,7 +137,10 @@ defmodule Scenic.Driver.Renderling.Window do end def handle_info(msg, driver) do - dbg(msg) + Logger.debug(fn -> + "Unhandled message #{inspect(msg)}" + end) + {:noreply, driver} end end diff --git a/mix.exs b/mix.exs index a5ff846..a57d59d 100644 --- a/mix.exs +++ b/mix.exs @@ -1,14 +1,38 @@ defmodule Scenic.Driver.Renderling.MixProject do use Mix.Project + @version "0.1.0" + @description """ + A Scenic driver which uses Rust's renderling crate to perform GPU-based rendering. + """ + def project do [ app: :scenic_driver_renderling, - version: "0.1.0", + version: @version, elixir: "~> 1.16", - elixirc_paths: elixirc_paths(Mix.env()), start_permanent: Mix.env() == :prod, - deps: deps() + package: package(), + description: @description, + deps: deps(), + elixirc_paths: elixirc_paths(Mix.env()), + docs: [ + main: "readme", + extras: ["README.md"] + ] + ] + end + + def package do + [ + maintainers: ["James Harton "], + licenses: ["HL3-FULL"], + links: %{ + "Source" => "https://harton.dev/james/scenic_driver_renderling", + "GitHub" => "https://github.com/jimsynz/scenic_driver_renderling", + "Changelog" => "https://docs.harton.nz/james/scenic_driver_renderling/changelog.html", + "Sponsor" => "https://github.com/sponsors/jimsynz" + } ] end @@ -22,9 +46,18 @@ defmodule Scenic.Driver.Renderling.MixProject do # Run "mix help deps" to learn about dependencies. defp deps do [ - {:rustler, "~> 0.32", runtime: false}, {:nimble_options, ">= 0.0.0"}, - {:scenic, "~> 0.11"} + {:rustler, "~> 0.32", runtime: false}, + {:scenic, "~> 0.11"}, + + # Dev/text + {:credo, "~> 1.6", only: ~w[dev test]a, runtime: false}, + {:dialyxir, "~> 1.4", only: ~w[dev test]a, runtime: false}, + {:doctor, "~> 0.21", only: ~w[dev test]a, runtime: false}, + {:ex_check, "~> 0.16", only: ~w[dev test]a, runtime: false}, + {:ex_doc, "~> 0.30", only: ~w[dev test]a, runtime: false}, + {:earmark, "~> 1.4", only: ~w[dev test]a, runtime: false}, + {:git_ops, "~> 2.4", only: ~w[dev test]a, runtime: false} ] end diff --git a/mix.lock b/mix.lock index f499361..d2acb6f 100644 --- a/mix.lock +++ b/mix.lock @@ -1,9 +1,26 @@ %{ + "bunt": {:hex, :bunt, "1.0.0", "081c2c665f086849e6d57900292b3a161727ab40431219529f13c4ddcf3e7a44", [:mix], [], "hexpm", "dc5f86aa08a5f6fa6b8096f0735c4e76d54ae5c9fa2c143e5a1fc7c1cd9bb6b5"}, + "credo": {:hex, :credo, "1.7.6", "b8f14011a5443f2839b04def0b252300842ce7388f3af177157c86da18dfbeea", [:mix], [{:bunt, "~> 0.2.1 or ~> 1.0", [hex: :bunt, repo: "hexpm", optional: false]}, {:file_system, "~> 0.2 or ~> 1.0", [hex: :file_system, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "146f347fb9f8cbc5f7e39e3f22f70acbef51d441baa6d10169dd604bfbc55296"}, + "decimal": {:hex, :decimal, "2.1.1", "5611dca5d4b2c3dd497dec8f68751f1f1a54755e8ed2a966c2633cf885973ad6", [:mix], [], "hexpm", "53cfe5f497ed0e7771ae1a475575603d77425099ba5faef9394932b35020ffcc"}, + "dialyxir": {:hex, :dialyxir, "1.4.3", "edd0124f358f0b9e95bfe53a9fcf806d615d8f838e2202a9f430d59566b6b53b", [:mix], [{:erlex, ">= 0.2.6", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "bf2cfb75cd5c5006bec30141b131663299c661a864ec7fbbc72dfa557487a986"}, + "doctor": {:hex, :doctor, "0.21.0", "20ef89355c67778e206225fe74913e96141c4d001cb04efdeba1a2a9704f1ab5", [:mix], [{:decimal, "~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}], "hexpm", "a227831daa79784eb24cdeedfa403c46a4cb7d0eab0e31232ec654314447e4e0"}, + "earmark": {:hex, :earmark, "1.4.46", "8c7287bd3137e99d26ae4643e5b7ef2129a260e3dcf41f251750cb4563c8fb81", [:mix], [], "hexpm", "798d86db3d79964e759ddc0c077d5eb254968ed426399fbf5a62de2b5ff8910a"}, + "earmark_parser": {:hex, :earmark_parser, "1.4.39", "424642f8335b05bb9eb611aa1564c148a8ee35c9c8a8bba6e129d51a3e3c6769", [:mix], [], "hexpm", "06553a88d1f1846da9ef066b87b57c6f605552cfbe40d20bd8d59cc6bde41944"}, "elixir_make": {:hex, :elixir_make, "0.7.8", "505026f266552ee5aabca0b9f9c229cbb496c689537c9f922f3eb5431157efc7", [:mix], [{:castore, "~> 0.1 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:certifi, "~> 2.0", [hex: :certifi, repo: "hexpm", optional: true]}], "hexpm", "7a71945b913d37ea89b06966e1342c85cfe549b15e6d6d081e8081c493062c07"}, + "erlex": {:hex, :erlex, "0.2.6", "c7987d15e899c7a2f34f5420d2a2ea0d659682c06ac607572df55a43753aa12e", [:mix], [], "hexpm", "2ed2e25711feb44d52b17d2780eabf998452f6efda104877a3881c2f8c0c0c75"}, + "ex_check": {:hex, :ex_check, "0.16.0", "07615bef493c5b8d12d5119de3914274277299c6483989e52b0f6b8358a26b5f", [:mix], [], "hexpm", "4d809b72a18d405514dda4809257d8e665ae7cf37a7aee3be6b74a34dec310f5"}, + "ex_doc": {:hex, :ex_doc, "0.32.2", "f60bbeb6ccbe75d005763e2a328e6f05e0624232f2393bc693611c2d3ae9fa0e", [:mix], [{:earmark_parser, "~> 1.4.39", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_c, ">= 0.1.0", [hex: :makeup_c, repo: "hexpm", optional: true]}, {:makeup_elixir, "~> 0.14 or ~> 1.0", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1 or ~> 1.0", [hex: :makeup_erlang, repo: "hexpm", optional: false]}, {:makeup_html, ">= 0.1.0", [hex: :makeup_html, repo: "hexpm", optional: true]}], "hexpm", "a4480305cdfe7fdfcbb77d1092c76161626d9a7aa4fb698aee745996e34602df"}, "ex_image_info": {:hex, :ex_image_info, "0.2.4", "610002acba43520a9b1cf1421d55812bde5b8a8aeaf1fe7b1f8823e84e762adb", [:mix], [], "hexpm", "fd1a7e02664e3b14dfd3b231d22fdd48bd3dd694c4773e6272b3a6228f1106bc"}, + "file_system": {:hex, :file_system, "1.0.0", "b689cc7dcee665f774de94b5a832e578bd7963c8e637ef940cd44327db7de2cd", [:mix], [], "hexpm", "6752092d66aec5a10e662aefeed8ddb9531d79db0bc145bb8c40325ca1d8536d"}, "font_metrics": {:hex, :font_metrics, "0.5.1", "10ce0b8b1bf092a2d3d307e05a7c433787ae8ca7cd1f3cf959995a628809a994", [:mix], [{:nimble_options, "~> 0.3", [hex: :nimble_options, repo: "hexpm", optional: false]}], "hexpm", "192e4288772839ae4dadccb0f5b1d5c89b73a0c3961ccea14b6181fdcd535e54"}, + "git_cli": {:hex, :git_cli, "0.3.0", "a5422f9b95c99483385b976f5d43f7e8233283a47cda13533d7c16131cb14df5", [:mix], [], "hexpm", "78cb952f4c86a41f4d3511f1d3ecb28edb268e3a7df278de2faa1bd4672eaf9b"}, + "git_ops": {:hex, :git_ops, "2.6.1", "cc7799a68c26cf814d6d1a5121415b4f5bf813de200908f930b27a2f1fe9dad5", [:mix], [{:git_cli, "~> 0.2", [hex: :git_cli, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.0", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "ce62d07e41fe993ec22c35d5edb11cf333a21ddaead6f5d9868fcb607d42039e"}, "jason": {:hex, :jason, "1.4.1", "af1504e35f629ddcdd6addb3513c3853991f694921b1b9368b0bd32beb9f1b63", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "fbb01ecdfd565b56261302f7e1fcc27c4fb8f32d56eab74db621fc154604a7a1"}, + "makeup": {:hex, :makeup, "1.1.2", "9ba8837913bdf757787e71c1581c21f9d2455f4dd04cfca785c70bbfff1a76a3", [:mix], [{:nimble_parsec, "~> 1.2.2 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "cce1566b81fbcbd21eca8ffe808f33b221f9eee2cbc7a1706fc3da9ff18e6cac"}, + "makeup_elixir": {:hex, :makeup_elixir, "0.16.2", "627e84b8e8bf22e60a2579dad15067c755531fea049ae26ef1020cad58fe9578", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.2.3 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "41193978704763f6bbe6cc2758b84909e62984c7752b3784bd3c218bb341706b"}, + "makeup_erlang": {:hex, :makeup_erlang, "1.0.0", "6f0eff9c9c489f26b69b61440bf1b238d95badae49adac77973cbacae87e3c2e", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "ea7a9307de9d1548d2a72d299058d1fd2339e3d398560a0e46c27dab4891e4d2"}, "nimble_options": {:hex, :nimble_options, "0.5.2", "42703307b924880f8c08d97719da7472673391905f528259915782bb346e0a1b", [:mix], [], "hexpm", "4da7f904b915fd71db549bcdc25f8d56f378ef7ae07dc1d372cbe72ba950dce0"}, + "nimble_parsec": {:hex, :nimble_parsec, "1.4.0", "51f9b613ea62cfa97b25ccc2c1b4216e81df970acd8e16e8d1bdc58fef21370d", [:mix], [], "hexpm", "9c565862810fb383e9838c1dd2d7d2c437b3d13b267414ba6af33e50d2d1cf28"}, "rustler": {:hex, :rustler, "0.32.1", "f4cf5a39f9e85d182c0a3f75fa15b5d0add6542ab0bf9ceac6b4023109ebd3fc", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:toml, "~> 0.6", [hex: :toml, repo: "hexpm", optional: false]}], "hexpm", "b96be75526784f86f6587f051bc8d6f4eaff23d6e0f88dbcfe4d5871f52946f7"}, "scenic": {:hex, :scenic, "0.11.2", "5d29aac74ee85899651716af47f72d167d064939fc2b4e514cd7c43810293cda", [:make, :mix], [{:elixir_make, "~> 0.7.7", [hex: :elixir_make, repo: "hexpm", optional: false]}, {:ex_image_info, "~> 0.2.4", [hex: :ex_image_info, repo: "hexpm", optional: false]}, {:font_metrics, "~> 0.5.0", [hex: :font_metrics, repo: "hexpm", optional: false]}, {:nimble_options, "~> 0.3.4 or ~> 0.4.0 or ~> 0.5.0 or ~> 1.0", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:truetype_metrics, "~> 0.6", [hex: :truetype_metrics, repo: "hexpm", optional: false]}], "hexpm", "6f846cfe8457163d28ad6b8b147d251bd15524c249ddad3e75608cbdb739beaa"}, "toml": {:hex, :toml, "0.7.0", "fbcd773caa937d0c7a02c301a1feea25612720ac3fa1ccb8bfd9d30d822911de", [:mix], [], "hexpm", "0690246a2478c1defd100b0c9b89b4ea280a22be9a7b313a8a058a2408a2fa70"},