Repository navigation
Conversation
|
@mvanhorn thanks for this PR, I think we can simplify this by using Are you currently using this library? |
|
Updated in 5fc9f84: syntax colors are now read with To answer your question: no, I'm not using the library myself. I picked up #26 to contribute. If compile-time configuration isn't the direction you want, I'm happy to close this. |
Schultzer
left a comment
There was a problem hiding this comment.
Thanks, we're almost there. I imagine this feature to be around 13 lines of additions.
Also @mvanhorn can you tell me how you work now a days, obvisouly there is an agent behind this, but I'm not sure if there is a human in this loop.
| @error IO.ANSI.red() | ||
| @reset IO.ANSI.reset() | ||
| @keyword IO.ANSI.magenta() | ||
| @literal IO.ANSI.yellow() | ||
| @enclosed IO.ANSI.green() |
There was a problem hiding this comment.
No need to move the code around just change these to:
| @error IO.ANSI.red() | |
| @reset IO.ANSI.reset() | |
| @keyword IO.ANSI.magenta() | |
| @literal IO.ANSI.yellow() | |
| @enclosed IO.ANSI.green() | |
| @error Application.compile_env(:sql, [:syntax_colors, :error], IO.ANSI.red())) | |
| @reset IO.ANSI.reset() | |
| @keyword Application.compile_env(:sql, [:syntax_colors, :keyword], IO.ANSI.magenta())) | |
| @literal Application.compile_env(:sql, [:syntax_colors, :literal], IO.ANSI.yellow())) | |
| @enclosed Application.compile_env(:sql, [:syntax_colors, :enclosed], IO.ANSI.green())) |
reset should not be configured.
| newline(color(color, [keyword(case, unquote(atom)),?\s,keyword(case, atom)], [?\n|to_iodata(values, color, case, errors, indent+1, acc)]), indent) | ||
| else | ||
| newline([@keyword, keyword(case, unquote(atom)),?\s,keyword(case, atom),@reset|to_iodata(values, color, case, errors, indent, acc)], indent) | ||
| newline(color(color, [keyword(case, unquote(atom)),?\s,keyword(case, atom)], to_iodata(values, color, case, errors, indent, acc)), indent) |
There was a problem hiding this comment.
You don't need to change this.
| defmodule SQL.Inspect do | ||
| @moduledoc false | ||
|
|
||
| @error IO.ANSI.red() |
There was a problem hiding this comment.
| @error IO.ANSI.red() | |
| @error Application.compile_env(:sql, [:syntax_colors, :error], IO.ANSI.red())) | |
| @reset IO.ANSI.reset() |
reset should not be configured.
| # SPDX-License-Identifier: Apache-2.0 | ||
| # SPDX-FileCopyrightText: 2025 DBVisor | ||
|
|
||
| defmodule SQL.SyntaxColorsTest do | ||
| use ExUnit.Case, async: false | ||
|
|
||
| setup do | ||
| original = Application.fetch_env(:sql, :syntax_colors) | ||
|
|
||
| on_exit(fn -> | ||
| case original do | ||
| {:ok, colors} -> Application.put_env(:sql, :syntax_colors, colors) | ||
| :error -> Application.delete_env(:sql, :syntax_colors) | ||
| end | ||
|
|
||
| recompile() | ||
| end) | ||
|
|
||
| Application.delete_env(:sql, :syntax_colors) | ||
| recompile() | ||
| :ok | ||
| end | ||
|
|
||
| test "default palette" do | ||
| formatted = formatted("select +1000", true) | ||
| assert formatted =~ "\e[35mselect\e[0m" | ||
| assert formatted =~ "\e[33m1000\e[0m" | ||
| end | ||
|
|
||
| test "partial override keeps unspecified roles" do | ||
| configure(keyword: :cyan) | ||
| formatted = formatted("select +1000", true) | ||
| assert formatted =~ "\e[36mselect\e[0m" | ||
| assert formatted =~ "\e[33m1000\e[0m" | ||
| end | ||
|
|
||
| test "runtime changes do not affect compiled colors" do | ||
| configure(keyword: [:bright, :cyan]) | ||
| Application.put_env(:sql, :syntax_colors, keyword: :blue) | ||
| assert formatted("select +1000", true) =~ "\e[1m\e[36mselect\e[0m" | ||
| end | ||
|
|
||
| test "enclosed quotes" do | ||
| assert formatted("select 'abc'", true) =~ "\e[32mabc\e[0m" | ||
|
|
||
| configure(enclosed: :cyan) | ||
| assert formatted("select 'abc'", true) =~ "\e[36mabc\e[0m" | ||
| end | ||
|
|
||
| test "color false emits no ansi" do | ||
| configure(keyword: :cyan, literal: :blue) | ||
| formatted = formatted("select +1000", false) | ||
| refute formatted =~ "\e[" | ||
| end | ||
|
|
||
| test "error nodes" do | ||
| {context, tokens} = parse("select users") | ||
| [{:select, _, [ident]}] = tokens | ||
| context = %{context | errors: [ident]} | ||
| formatted = IO.iodata_to_binary(SQL.Format.to_iodata(tokens, context, 0, true)) | ||
| assert formatted =~ "\e[31musers\e[0m" | ||
|
|
||
| configure(error: :blue) | ||
| formatted = IO.iodata_to_binary(SQL.Format.to_iodata(tokens, context, 0, true)) | ||
| assert formatted =~ "\e[34musers\e[0m" | ||
|
|
||
| warning = IO.iodata_to_binary(SQL.Inspect.format_error([{:ident, [], "users"}])) | ||
| assert warning =~ "the relation \e[34musers\e[0m does not exist" | ||
| end | ||
|
|
||
| test "unknown color raises" do | ||
| assert_raise ArgumentError, fn -> | ||
| configure(keyword: :not_a_color) | ||
| end | ||
| end | ||
|
|
||
| defp configure(colors) do | ||
| Application.put_env(:sql, :syntax_colors, colors) | ||
| recompile() | ||
| end | ||
|
|
||
| defp recompile do | ||
| options = Code.compiler_options(ignore_module_conflict: true) | ||
|
|
||
| try do | ||
| Code.compile_file("lib/format.ex") | ||
| Code.compile_file("lib/inspect.ex") | ||
| after | ||
| Code.compiler_options(options) | ||
| end | ||
| end | ||
|
|
||
| defp parse(sql) do | ||
| {:ok, context, tokens} = SQL.Lexer.lex(sql) | ||
| {:ok, context, tokens} = SQL.Parser.parse(tokens, context) | ||
| {context, tokens} | ||
| end | ||
|
|
||
| defp formatted(sql, color) do | ||
| {context, tokens} = parse(sql) | ||
| IO.iodata_to_binary(SQL.Format.to_iodata(tokens, context, 0, color)) | ||
| end | ||
| end |
There was a problem hiding this comment.
We already have tests for the inspect, so these test are not nedded, also they are testing Elixir more then our implementation.
| ## Syntax highlighting | ||
|
|
||
| Inspect output and compile-time warnings color keywords, literals, enclosed quotes, and errors. Override any of those roles from `config.exs`: | ||
|
|
||
| ```elixir | ||
| config :sql, :syntax_colors, [keyword: :cyan, literal: :yellow, enclosed: :green, error: :red] | ||
| ``` | ||
|
|
||
| Each value is an `IO.ANSI` color name or a list of them. Roles you omit keep the defaults: magenta keywords, yellow literals, green enclosed quotes, and red errors. Colors are read when the SQL library compiles, so this setting belongs in `config.exs`; recompile the library after changing it (for a dependency, run `mix deps.compile sql --force`). Recompile callers with static `~SQL` sigils as well, since they store their inspect text at compilation. | ||
|
|
There was a problem hiding this comment.
We need to adjust these to the suggestions I gave above, we can also make this more consice, no need for the last paragraph.
|
@mvanhorn please do me a favor and just amend the first commit in this PR with all the changes, no need for multiple commits for this feature. |
e1e54f3 to
e260f74
Compare
|
@Schultzer Updated and squashed into the first commit, so the PR is now a single commit.
The code change is 5 lines now; with the README and CHANGELOG it's 22 additions. mix compile --warnings-as-errors and mix test are clean (397 tests). On how I work: I use AI coding agents to draft the changes and the replies, and I review and approve every commit and comment before it goes out, including this one. If you'd rather work with me differently on this PR, happy to adjust. |
Thanks, just a rebase and we should be good to merge this. |
Read the keyword, literal, enclosed, and error colors from config :sql, :syntax_colors with Application.compile_env, falling back to the current IO.ANSI defaults. The reset sequence stays fixed. Fixes elixir-dbvisor#26 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019wSaUMZrtm6XSzwEcxavkv
e260f74 to
3c23785
Compare
|
Rebased on main (3c23785). The only conflict was CHANGELOG.md, so the entry now sits under a new Unreleased section above v0.6.0. mix test passes locally. |
SQL.Format.syntax_color/1 reads :syntax_colors from the :sql application environment and turns a color name, or a list of them, into an ANSI fragment with IO.ANSI.format_fragment. Formatted SQL and the compile-time warnings that quote it always highlight keywords, literals, enclosed quotes, and errors with the same ANSI colors.
Tests for this live in
test/syntax_colors_test.exs.Closes #26