Skip to content

Separate types from constants in Ruby syntax highlighting - #237

Merged
shugo merged 5 commits into
mainfrom
fix/ruby-separate-type-from-const
Mar 23, 2026
Merged

Separate types from constants in Ruby syntax highlighting#237
shugo merged 5 commits into
mainfrom
fix/ruby-separate-type-from-const

Conversation

@shugo

@shugo shugo commented Mar 23, 2026

Copy link
Copy Markdown
Owner

Treat a constant name as a type if it contains lower-case characters, following GitHub's convention.

shugo added 2 commits March 23, 2026 13:36
Treat a constant name as a type if it contains lower-case characters, following GitHub's convention.
To avoid them being treated as types.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adjusts Ruby syntax highlighting to distinguish “type-like” constants (CamelCase) from “value” constants (ALL_CAPS), aligning with GitHub’s visual convention.

Changes:

  • Update Ruby mode highlighting to render constants containing lowercase characters using the :type face.
  • Adjust GitHub theme colors to swap :constant/:type colors to match the new classification.
  • Update tests (and a default encoding list) to reflect the new highlighting and encoding constant casing changes.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
lib/textbringer/modes/ruby_mode.rb Adds lowercase-detection heuristic to classify constants as :type.
lib/textbringer/themes/github.rb Swaps :constant and :type face colors.
test/textbringer/modes/test_ruby_mode.rb Updates highlight expectation for Foo::BAR to treat Foo as :type.
lib/textbringer/buffer.rb Changes default auto-detect encoding constant casing for Windows-31J.
test/textbringer/test_buffer.rb Updates encoding constants in buffer tests to new casing.
test/textbringer/commands/test_files.rb Updates encoding assertions to new casing.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread lib/textbringer/buffer.rb
Encoding::UTF_8,
Encoding::EUC_JP,
Encoding::Windows_31J
Encoding::WINDOWS_31J

Copilot AI Mar 23, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Encoding::WINDOWS_31J relies on Encoding constant-name lookup/normalization (often via const_missing) rather than the canonical constant name, which can vary across Ruby versions. Since this project supports Ruby >= 3.2, consider using Encoding.find("Windows-31J") (already used elsewhere in Buffer) or the canonical Encoding::Windows_31J to avoid version-dependent constant casing.

Suggested change
Encoding::WINDOWS_31J
Encoding.find("Windows-31J")

Copilot uses AI. Check for mistakes.
Comment on lines 800 to +807
def test_save_windows31j
Tempfile.create("test_buffer", binmode: true) do |f|
f.print(<<EOF.encode(Encoding::Windows_31J))
f.print(<<EOF.encode(Encoding::WINDOWS_31J))
こんにちは
EOF
f.close
buffer = Buffer.open(f.path)
assert_equal(Encoding::Windows_31J, buffer.file_encoding)
assert_equal(Encoding::WINDOWS_31J, buffer.file_encoding)

Copilot AI Mar 23, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tests now reference Encoding::WINDOWS_31J. If this casing is only to influence syntax highlighting, it may be better to keep tests using the canonical encoding constant (or Encoding.find("Windows-31J")) to avoid depending on Encoding’s constant-name normalization behavior across Ruby versions.

Copilot uses AI. Check for mistakes.
revert_buffer_with_encoding("Windows-31J")
assert_equal("、「、、、ヲ、ィ、ェ\n", Buffer.current.to_s)
assert_equal(Encoding::Windows_31J, Buffer.current.file_encoding)
assert_equal(Encoding::WINDOWS_31J, Buffer.current.file_encoding)

Copilot AI Mar 23, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Encoding::WINDOWS_31J here may depend on Ruby’s Encoding constant-name normalization. For compatibility with the stated Ruby support range, consider asserting against Encoding.find("Windows-31J") (or the canonical Encoding::Windows_31J) instead of relying on a particular constant casing.

Suggested change
assert_equal(Encoding::WINDOWS_31J, Buffer.current.file_encoding)
assert_equal(Encoding.find("Windows-31J"), Buffer.current.file_encoding)

Copilot uses AI. Check for mistakes.
Comment thread lib/textbringer/modes/ruby_mode.rb Outdated
face_name = :function_name if type == :IDENTIFIER ||
type == :CONSTANT || type == :METHOD_NAME ||
PRISM_TOKEN_FACES[type] == :operator
elsif face_name == :constant && token.location.slice.match?(/[a-z]/)

Copilot AI Mar 23, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new heuristic checks only ASCII lowercase (/[a-z]/). Ruby constants can include non-ASCII letters, so this won’t fully implement “contains lower-case characters”. Consider switching to a Unicode-aware pattern like /[[:lower:]]/ or /\p{Lower}/ to match lowercase letters consistently.

Suggested change
elsif face_name == :constant && token.location.slice.match?(/[a-z]/)
elsif face_name == :constant && token.location.slice.match?(/[[:lower:]]/)

Copilot uses AI. Check for mistakes.
@shugo
shugo force-pushed the fix/ruby-separate-type-from-const branch from e09bb98 to 518e393 Compare March 23, 2026 05:26
@shugo
shugo force-pushed the fix/ruby-separate-type-from-const branch from 01a50a7 to 9c348f0 Compare March 23, 2026 05:40
@shugo
shugo requested a review from Copilot March 23, 2026 05:41

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 6 out of 6 changed files in this pull request and generated 1 comment.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread lib/textbringer/modes/ruby_mode.rb Outdated
face = Face[face_name]
next unless face
ctx.highlight(pos, pos_end, face)
after_class_or_module = (type == :KEYWORD_CLASS || type == :KEYWORD_MODULE)

Copilot AI Mar 23, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

after_class_or_module is only set for the current token (type == :KEYWORD_CLASS || :KEYWORD_MODULE), so it won’t carry across tokens that can appear between class/module and the actual constant(s) being defined (e.g. class ::X, class X::Y, class X < Y, or intervening comments/newlines depending on Prism tokenization). This can cause some class/module names (or namespaced segments) to be highlighted as :constant instead of :type. Consider making this state persist until the end of the class/module header (e.g., carry through COLON_COLON, superclass <, and similar tokens, and reset on statement terminators like NEWLINE/SEMICOLON). Adding a test for class ::X or class X::Y would lock in the intended behavior.

Suggested change
after_class_or_module = (type == :KEYWORD_CLASS || type == :KEYWORD_MODULE)
if type == :KEYWORD_CLASS || type == :KEYWORD_MODULE
after_class_or_module = true
elsif after_class_or_module
# Stay in "after class/module" state until a statement terminator.
after_class_or_module = !(type == :NEWLINE || type == :SEMICOLON)
else
after_class_or_module = false
end

Copilot uses AI. Check for mistakes.
@shugo
shugo merged commit 61922ca into main Mar 23, 2026
7 checks passed
@shugo
shugo deleted the fix/ruby-separate-type-from-const branch March 23, 2026 06:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants