Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Introduce a new class Reline::Face to configure character attributes #552

Merged
merged 34 commits into from Nov 6, 2023

Conversation

hasumikin
Copy link
Collaborator

I made this PR to restart discussing the color configuration of Reline.

The original issue is https://bugs.ruby-lang.org/issues/18996

Summary of this PR

  • Decouples interest in character attributes from Reline::DialogRenderInfo
  • To do it, introduces a new classReline::Face that manages sets of character attributes based on Select Graphic Rendition (SGR)
  • You can now specify 256 colors by an RGB value like "#3300aa" (actual result depending on your terminal emulator)
  • As in, you are able to specify attributes other than a color like :underlined and :negative
  • This patch itself doesn't change the current external behavior of IRB by default
  • This PR does not fully resolve the code consistency between Reline and IRB. Further discussions and development are needed

Background

  • Reline::DialogRenderInfo currently accepts these text color attributes:
    • :bg_color
    • :pointer_bg_color
    • :fg_color
    • :pointer_fg_color
  • It is an incomplete implementation because you can't specify attributes other than color such as "bold", "underline", and "blink"
  • This situation makes us difficult to discuss text color
  • On terminal emulators, "text color" belongs to the CSI sequences
  • I think that DialogRenderInfo should not worry about escape sequences

Why "Face"?

My respected @shugo kindly advised me to refer to the Face of Textbringer (and Emacs): https://github.com/shugo/textbringer/blob/main/lib/textbringer/faces/programming.rb

Naming attributes

I know that Ruby core members gently agreed with a suggestion about naming here:
https://bugs.ruby-lang.org/issues/18996#note-8

However, as this PR shows, Reline::Face can focus on only the character attribute of the terminal emulator which is described in "8.3.117 SGR - SELECT GRAPHIC RENDITION" of the ECMA-48 standard: https://www.ecma-international.org/wp-content/uploads/ECMA-48_5th_edition_june_1991.pdf

I think it would make us pick the names again from the ECMA-48.
This is the reason that I use "display" instead of "foreground".
Likewise, the other attributes like :italicized and :underlined were picked from the ECMA-48 standard.

To be honest, I also think that "foreground" is more widely used.
Textbringer also uses "foreground".
However, I myself am not aware of any authorized documents that provide a basis for us to adopt "foreground" instead of "display".

Even if so, you can still recommend "foreground".
Let me hear your opinion.

Other points where I want your opinion

  • Reline::Face::SGR_PARAMETERS
    • The attributes that Reline::Face currently accepts are my really arbitrary choice. For example, I have omitted "doubly underlined" because I don't think it's widely supported
    • As in, if there are two variants of the same kind, I added a shorthand alias for the more widely supported one. For example, :blinking is an alias for :slowly_blinking while no alias for :rapidly_blinking
    • Also, :gray_ is an alias for :bright_black_
  • RGB literal like "#ffffff" is strictly checked with /\A#[0-9a-fA-F]{6}\z/ though, a value like "ffffff" (omitting #) might be valid as well
  • I don't think that face labels :normal_line and :enhanced_line are perfectly right to the point. But at least I think that the word "selected" refers to a concept of "Completion dialog" and is not a universal concept among all kinds of dialog
  • Method name define, etc. Advise me on anything :)

Reline::Face in .irbrc

IRB's completion dialog in my terminal looks like this by default:

image

If you feel the color contrast of the dialog above is too low to see, you can write the following in .irbrc:

# Change cyan to blue
Reline::Face.config(:completion_dialog) do |face|
  face.define :normal_line, :white_display, :blue_background
  face.define :enhanced_line, :white_display, :magenta_background
  face.define :scrollbar, :white_display, :blue_background
end

image

This looks nice, too:

# Use "negative"
Reline::Face.config(:completion_dialog) do |face|
  face.define :normal_line, :white_display, :blue_background
  face.define :enhanced_line, :white_display, :blue_background, :negative
  face.define :scrollbar, :white_display, :blue_background
end

image

Note

Making able to configure the character attributes in .irbrc is not my original purpose.
If you feel it's too rushed to make it a public API, let's discuss it.

Future plan (not by this PR)

As they say, .irbrc is possibly dangerous.

So you may want to put a file like ~/.irbrc.yaml that looks like this:

reline:
  face:
    completion_dialog:
      line:
        - white_display
        - blue_background
      enhanced_line:
        - white_display
        - background: "#885500"
    documentation_dialog:
      # I don't mean this configuration is appropriate. Just a casual idea
      headline:
        - green_display
      body:
        - white_display
      note:
        - bright_yellow_display
        - bold
      link:
        - blue_display
        - underlined

It'd be supposed to be done by another big discussion and some PRs to IRB.

Other remaining issues

@hasumikin hasumikin requested a review from a team June 13, 2023 10:02
Copy link
Member

@shugo shugo left a comment

Choose a reason for hiding this comment

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

👍

@ima1zumi ima1zumi added the enhancement New feature or request label Jun 13, 2023
@hasumikin hasumikin changed the title Introduce a new class Reine::Face to configure character attributes Introduce a new class Reline::Face to configure character attributes Jun 13, 2023
@tompng
Copy link
Member

tompng commented Jun 18, 2023

I'd be happy if it can fallback to nearest 256 palette color, maybe in the future, because macOS Terminal.app which I usually use does not support 256**3 color.

when Symbol
SGR_PARAMETERS.keys.include?(sgr_value)
when Hash
sgr_value.count == 1 or return false
Copy link
Member

Choose a reason for hiding this comment

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

API usage is like this

face.define :enhanced_line, { display: '#abcdef' }, { background: '#fedcba' }, :bold, :italicized
face.define :enhanced_line, { display: '#abcdef' }, :bright_blue_background, :underlined

I think it's good. I especialy like that YAML format will be simple.

However, I thought if I can define it like this

# Single hash or keyword parameter
face.define :enhanced_line, display: '#abcdef', background: '#fedcba'
# Use both hex-color and color name
face.define :enhanced_line, display: '#012345', background: :bright_blue
# Need to be able to specify other styles, so
face.define :enhanced_line, display: :white, background: :blue, styles: [:bold, :italicized]

What do you think?

@st0012
Copy link
Member

st0012 commented Jun 18, 2023

Thank you for the proposal and the detailed description 🙏
I haven't dug into the implementation yet, but here are some thoughts about the proposal:

  • I like the ability to specify more styles than colours 👍
  • How hard would it be to maintain compatibilities for RGB value between terminal emulators?
  • Face is not a straightforward name to me. And it also doesn't seem to be used very often? For example, I can't find any configs named with *face* in iTerm2's settings. In VSCode's settings, I also don't see any style-related attributes named with *face* in it besides fontface.
    • I prefer using more common words Style or Display as the namespace.
  • Wrt display vs foreground, I feel we should go with foreground as many of the best-known develoepr tools like alacritty, iTerm2, VS Code all use it. In vim we also see fg as the shortcut for foreground.
  • For individual attributes, I prefer background: :blue over :blue_background because it could be hard to remember (for users) or maintain (for us) a long list of options & values combination.
  • For line states, if we feel selected is too restrictive, what other states do we provide or could provide in Reline?

Additional References

@hasumikin
Copy link
Collaborator Author

(I don't write this in a thread as I answer your both comments)

@tompng
Thanks!
I really agree that your suggestion looks more Rubyish.
I thought the same API I should make. It will work.

But one concern was that "style" does not only represent "bold" and "underlined" in ECMA-48. In other words, a color also belongs to "style" (Although ECMA-48 doesn't use the word "style" but "graphic rendition aspects").

As in, there is no rule about the order of the attribute in ECMA-48. We can specify a "style" in advance of a display color.
Colors (like red display and blue background) and "styles" (like bold and underlined) are equal in the Select Graphic Rendition.
That's why I suggested not introducing an attribute "style", unlike your suggestion that makes a kind of fixed order of the sequences.
I also wanted the API to be transparent to the CSI and SGR.
I guess this kind of design is more maintainable in case of finding an edge case. I suspect such kind of edge case may happen depending on the GRAPHIC RENDITION COMBINATION MODE of the terminal emulator where we have to keep a peculiar order of the text attributes.

This also relates to @st0012's suggestion of preferring "foreground" to "display". Half of my reason not to adopt "style" will go away if we adopt "foreground" because we'd no longer stick to ECMA-48 ;)

Therefore I propose that, first of all, we should decide to use "foreground" or "display".
This decision would probably make the rest of things clearer a bit.

@ima1zumi Please let us know your idea, too

@ima1zumi
Copy link
Member

ima1zumi commented Jul 4, 2023

@hasumikin
Inspired by @st0012 's comment, I looked into the configuration items of some well-known terminal emulators and others.
It seems that most of them are foreground and some of them can be set in the text field. It seems that display is not used. I think it would be better to use foreground.

I also wanted the API to be transparent to the CSI and SGR.

However, I find this idea fascinating. Could you please tell me more about how to make the API transparent to CSI and SGR?

@hasumikin
Copy link
Collaborator Author

hasumikin commented Jul 5, 2023

@ima1zumi

However, I find this idea fascinating. Could you please tell me more about how to make the API transparent to CSI and SGR?

My word "transparent" in my mind is explained in the comment above (let me quote again ↓):

But one concern was that "style" does not only represent "bold" and "underlined" in ECMA-48. In other words, a color also belongs to "style" (Although ECMA-48 doesn't use the word "style" but "graphic rendition aspects").

As in, there is no rule about the order of the attribute in ECMA-48. We can specify a "style" in advance of a display color.
Colors (like red display and blue background) and "styles" (like bold and underlined) are equal in the Select Graphic Rendition.
That's why I suggested not introducing an attribute "style", unlike your suggestion that makes a kind of fixed order of the sequences.

In short, introducing the styles attribute that @tompng suggests doesn't look "transparent" to me.

Even if we use "foreground" instead of "display", the "transparent" concept can work because they are basically orthogonal to each other, I think.

@hasumikin
Copy link
Collaborator Author

@st0012

  • How hard would it be to maintain compatibilities for RGB value between terminal emulators?

TBH I still don't know. I even feel we will now know for good... It's one of the reasons that I'm overall suggesting API which is "transparent" to ECMA-48 as much as possible.

  • Face is not a straightforward name to me. And it also doesn't seem to be used very often? For example, I can't find any configs named with face in iTerm2's settings. In VSCode's settings, I also don't see any style-related attributes named with face in it besides fontface.
    • I prefer using more common words Style or Display as the namespace.

It's the point. I believe the word "face" works well because it is not used very often.
At the same time, the word face has its own kind of tradition that is suitable to our requirement: https://www.gnu.org/software/emacs/manual/html_node/emacs/Faces.html

As you can see from our discussion, "style" and "display" are highly ambiguous and we should avoid those words in this case.

  • For line states, if we feel selected is too restrictive, what other states do we provide or could provide in Reline?

I suggested the word "enhanced" in this PR though, I am really open to discussing this concern.
I don't have a robust answer now.

@st0012
Copy link
Member

st0012 commented Jul 27, 2023

As you can see from our discussion, "style" and "display" are highly ambiguous and we should avoid those words in this case.

Honestly, I don't quite see it from that perspective. If you give me a class called Reline::Style, I would instinctively associate it with the visual presentation of elements.

The documentation seems to hint at this too, as it introduces faces right from the get-go with:

Emacs can display text in several different [styles], called faces.

That being said, given that Reline draws a lot of inspiration from Emacs, it seems logical to adopt similar terminology. Plus, as a class name, it's straightforward to recall and locate references to.

However, I do feel strongly about using the most commonly recognized names for attributes. So, to encapsulate my thoughts on naming conventions:

  • I'm leaning towards Reline::Style. But if the team prefers Reline::Face, I'm cool with that too.
  • I'd advocate for foreground_color or foreground instead of display when naming color attributes.
  • I'm a fan of key: value pairs for attributes, rather than :key_value.
  • I'd go for selected_ over enhanced_, but I'm not super passionate about this one.

@hasumikin
Copy link
Collaborator Author

@st0012
Thank you for the comment.
I'm sorry, recently I didn't have any free time.

Firstly I want us to decide whether we take 'Face' as the name of the class. Or should we choose another one?
My preference is still on 'Face' over 'Style' because the word 'Style' is associated with everything in all concepts of this feature, I think that the term for the class name needs to be unique.
What do you all think? @tompng @ima1zumi

@tompng
Copy link
Member

tompng commented Sep 5, 2023

I agree with @hasumikin that Style is too big concept and looks like it can be used for non-text styling too.

One little concern I have for Face is that the naming of Face reminds me of font-family.

  • CSS font-face is a definition of font-family
  • HTML face property of font tag <font face="Times"> is font family
  • The word Typeface means font family (from wikipedia)

I'm not strongly against Face. I like it, but I want to propose another naming TextAppearance.

@krmbzds
Copy link

krmbzds commented Sep 5, 2023

Reline::Style, foreground, selected_ and key: value pairs for attributes are the most sensible to me.

@ima1zumi
Copy link
Member

@hasumikin
Sorry for the delay in replying. I too feel that the term Style is too broad in meaning.
As for Face and TextAppearance, I rather prefer Face.
I believe it is a matter of decision as there does not seem to be a general concept to describe the text color setting of a device, and I like that Face is a short word.
However, I don't have strong feelings.

@hasumikin
Copy link
Collaborator Author

Thank you everyone for your comments.
It looks like Face was gently approved, I guess, right?
I think I'll go with the following policy:

The class name is Reline::Face

Amend display to foreground

As many of you prefer it. Tell me if you have another idea.

Amend snake case attributes like :blue_background to key-value pairs like background: :blue

As @tompng suggested here #552 (review)
But the word styles is another point again. I will mention it later.

As I wrote in #552 (comment), I was skeptical about taking key-value style because ECMA-48 doesn't stipulate such a nested structure (instead, everything is flat). I've been thinking if there is some fall pit of taking key-value style up to now though, I couldn't come up with. So I accept the key-value style. Yes, it is Rubyish.

Remaining points to discuss

:styles key

face.define :enhanced_line, display: :white, background: :blue, styles: [:bold, :italicized]
#                                                               ^^^^^^
  • Should it be a plural? I feel an uncountable (singular) is better.
  • Are there other words than "style(s)"? I feel "appearance" is also nice here. However, if we take a discipline of "Shorter is Better", "style" should be good to go. (Fortunately,?) The word "style" is not in use as the class name

"enhanced" vs "selected"

  face.define :enhanced_line, foreground: :white, background: :magenta
#              ^^^^^^^^

I don't think "selected" is good because it is too focused on our intention and action. A line that looks strong doesn't always mean we selected it, right?
I have some alternatives to "enhanced":

  • "highlighted" ...It'd be a good one but I feel like I'll TYPO, lol
  • "strong" ...Is shorter better?
  • ("bold" can't be used here because it is one of "style/appearance" in ECMA-48)

Also, we should think twice about "normal". I feel "default" may be better.

  face.define :normal_line, foreground: :white, background: :black
#              ^^^^^^

I now like "default - enhanced" pair ("default - strong" also looks good to me):

  face.define :default_line, foreground: :white, background: :black
  face.define :enhanced_line, foreground: :white, background: :magenta
# face.define :strong_line, foreground: :white, background: :magenta

Furthermore, "string" may be better than "line"

  face.define :default_string, foreground: :white, background: :black
  face.define :enhanced_string, foreground: :white, background: :magenta

Please tell me your opinion regarding the following points:

  • "styles" vs "style" vs "appearance" vs "???"
  • "enhanced" vs "selected" vs "highlighted" vs "strong" vs "???"
  • "normal" vs "default" vs "???"
  • "line" vs "string" vs "???"

@tompng
Copy link
Member

tompng commented Sep 15, 2023

"styles" vs "style" vs "appearance" vs "???"

I like singular style.
If we accept style: [:bold, :italicized] and also style: :bold, it looks wierd if the key is plural styles: :bold.

"enhanced" vs "selected" vs "highlighted" vs "strong" vs "???"

I like enhanced or strong. I agree selected is not good.

"normal" vs "default" vs "???"

I like default.

"line" vs "string" vs "???"

I prefer no suffix. Just :enhanced :default. For Face, it is always about text/line/string, so I prefer no suffix.
line looks like it is applied to all string in a line. string looks like it does not contain background.

@hasumikin
Copy link
Collaborator Author

No suffix would work. I'm fine with it.

How about you guys? @ima1zumi @st0012

@st0012
Copy link
Member

st0012 commented Sep 18, 2023

Similar to @tompng:

  • style
  • enhanced
  • default
  • no suffix
face.define :default, foreground: :white, background: :blue
face.define :enhanced, foreground: :black, background: :white, style: [:bold, :italicized]

@ima1zumi
Copy link
Member

  • style
  • highlighted or strong. Because I didn't understand what :enhance was until I read the code and set it.
  • default
  • no suffix

@hasumikin
Copy link
Collaborator Author

One final point on which opinions are conflicted:

I like enhanced or strong. I agree selected is not good.
(@tompng)

enhanced
(@st0012)

highlighted or strong. Because I didn't understand what :enhance was until I read the code and set it.
(@ima1zumi)

:enhanced seems to be the most popular.
We can also say that :strong may be better because @ima1zumi votes -1 for :enhanced.... 🤔

Maybe I will pick :enhanced as I prefer it. Please let me know if you have any additional comments.

sgr_rgb(key, value)
end
when :style
[ value ].flatten.map { |style_name| SGR_PARAMETERS[:style][style_name] }
Copy link
Member

Choose a reason for hiding this comment

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

If style contains :default, foreground and background is reset.
I think this is a little confusing

# red, cyan, bold
face.define :enhanced, background: :red, foreground: :cyan, style: :bold
# default background, default foreground
face.define :enhanced, background: :red, foreground: :cyan, style: :default

Other part of this pull request looks good to me 👍

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Yap, that's why I originally named :normal_line instead of :default 🥺

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

...How about style :reset ?

Copy link
Member

@tompng tompng Nov 3, 2023

Choose a reason for hiding this comment

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

RESET_SGR is always set at sgr == RESET_SGR ? RESET_SGR : RESET_SGR + sgr, so using SGR_PARAMETERS[:style][:default] or SGR_PARAMETERS[:style][:reset] here has no effect other than ignore foreground and background. I thought excluding :default is missing.

[ value ].flatten.flter_map do |style_name|
   SGR_PARAMETERS[:style][style_name] if style_name != :default
end

Copy link
Collaborator Author

@hasumikin hasumikin Nov 3, 2023

Choose a reason for hiding this comment

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

Okay, I got what you're saying.
Fortunately, I guess changing style: :default to style: :reset made the situation better.
5a53084
Parameters before :reset will be reset while parameters after :reset are not ignored because the order of the escape sequences will be the same as the order of the parameters in the format_to_sgr method.
example:

format_to_sgr({foreground: :white, style: :reset, background: :red})
=> "\e[0m\e[37;0;41m"

Since Reline users are programmers, I think there is no problem with them writing freely and taking responsibility for it.

Copy link
Member

Choose a reason for hiding this comment

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

Looks good.
Perhaps face.define :default, style: :default in reline.rb should be face.define :default, style: :reset?
It seems that invalid SGR parameter check is skipped for style

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

You are right 👍 67a8497

And I was wrong one more thing 😓c02205c

Copy link
Member

@st0012 st0012 left a comment

Choose a reason for hiding this comment

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

Just one suggestion on test cleanup. We're getting very close 👍
Also, do you know where to document this feature?

test/reline/test_face.rb Outdated Show resolved Hide resolved
test/reline/test_face.rb Outdated Show resolved Hide resolved

class WithInsufficientSetupTest < self
def setup
Reline::Face.config(:my_insufficient_config) do |face|
Copy link
Member

@st0012 st0012 Nov 3, 2023

Choose a reason for hiding this comment

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

For tests that call Reline::Face.config, should we also set its @configs to the Reline default in teardown?

Once merged, these tests will be ran on Ruby CI with other gems' tests in the same process. So if Reline::Face.configs change over tests, it may cause other tests to fail. I broke Ruby CI many times because of things like this 😅

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Existing tests don't override configs of :default and :completion_dialog which are possible to be used by other tests, so I don't think Ruby CI will break without teardown...maybe

On the other hand, it is also good to make the teardown process in advance I carelessly write a test that overrides the default config in the future.
Will it look like this?:

# lib/reline/face.rb
class Reline::Face
  def self.reset_config
    @configs = {}
    Reline::Face.config(:default) do |face|
      face.define :default, style: :reset
      face.define :enhanced, style: :reset
      face.define :scrollbar, style: :reset
    end
    Reline::Face.config(:completion_dialog) do |face|
      face.define :default, foreground: :white, background: :cyan
      face.define :enhanced, foreground: :white, background: :magenta
      face.define :scrollbar, foreground: :white, background: :cyan
    end
  end
end

# test/reline/test_face.rb
class Reline::Face::Test < Reline::TestCase
  def teardown
     Reline::Face.reset_config
  end
end

I can't say if I should do this now or not. What do you think?

Copy link
Member

Choose a reason for hiding this comment

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

That's a good idea. But I also want to use this method in reline.rb to make sure the default there is always the same as what we reset.

How about:

class Reline::Face
  def self.apply_default_configs
    @configs = {}
    Reline::Face.config(:default) do |face|
      face.define :default, style: :reset
      face.define :enhanced, style: :reset
      face.define :scrollbar, style: :reset
    end
    Reline::Face.config(:completion_dialog) do |face|
      face.define :default, foreground: :white, background: :cyan
      face.define :enhanced, foreground: :white, background: :magenta
      face.define :scrollbar, foreground: :white, background: :cyan
    end
  end
end

# In reline.rb

Reline::Face.apply_default_configs

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

23d2360

I separated the initializing method into reset_to_initial_config and load_initial_config so that a user can only reset the "initial" config (:default and :completion_dialog) without losing definitions by the user.

initial vs default

I chose the word "initial" instead of "default" to avoid ambiguity because "default" is used elsewhere.

config vs configs

In this case, no need for users to think about how many settings exist. So I think the singular "config" is enough and better.

Copy link
Member

Choose a reason for hiding this comment

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

I chose the word "initial" instead of "default" to avoid ambiguity because "default" is used elsewhere.

👍

In this case, no need for users to think about how many settings exist. So I think the singular "config" is enough and better.

I'm not sure if I agree. Using config means explicitly "there's only 1 config", which is simply incorrect in this case. But using configs actually could mean 1 or more.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I initially said "singular," but upon closer consideration, "uncountable" seems more appropriate. Therefore, I don't believe a plural form is necessary.

Copy link
Member

Choose a reason for hiding this comment

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

I still don't get it. config is never uncountable. Otherwise, we wouldn't have Reline::Face.configs, no?

Even if we do want to consider it uncountable for this API, it's more confusing to have both countable and uncountable form of the same word in the same project, especially on the same component:

Reline::Face.load_initial_config #=> looks like it's loading a single config
Reline::Face.configs #=> returns 2 values?

The fact is that we do load 2 configs when calling that method, and we do call configs when retrieving them. Why insisting it being called either singular or uncountable?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I see, fixed 7c5133c

@hasumikin
Copy link
Collaborator Author

Also, do you know where to document this feature?

We may have to do a major rewrite of this document.
https://docs.ruby-lang.org/en/master/IRB.html

However, since overall rewriting of the doc will be a big task, it may be practical to write a document in github.com/ruby/reline/doc/reline/face.md
and publish under https://docs.ruby-lang.org/en/
for the time being.

What do you think? @tompng @ima1zumi

hasumikin and others added 2 commits November 4, 2023 22:34
Co-authored-by: Stan Lo <stan001212@gmail.com>
Co-authored-by: Stan Lo <stan001212@gmail.com>
@st0012
Copy link
Member

st0012 commented Nov 4, 2023

I don't think this should be documented on the IRB side because other Reline users like debug can also use it. The simplest way for now could be to write it in this project's README under a Configuration section, perhaps along with a few other commonly used options, like:

  • Reline.autocompletion
  • Reline.dig_perfect_match_proc
  • Reline.output_modifier_proc
  • Reline.completion_proc
  • ....etc.

@hasumikin
Copy link
Collaborator Author

OK, let's discuss here
#598

@hasumikin
Copy link
Collaborator Author

Added a doc hasumikin@76dd7b0

doc/reline/face.md Outdated Show resolved Hide resolved
lib/reline/face.rb Outdated Show resolved Hide resolved
Comment on lines +141 to +145
config(:default) do |conf|
conf.define :default, style: :reset
conf.define :enhanced, style: :reset
conf.define :scrollbar, style: :reset
end
Copy link
Member

Choose a reason for hiding this comment

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

What is this config required for? It does not appear to be used.
Sorry if I have missed it.

Copy link
Collaborator Author

@hasumikin hasumikin Nov 6, 2023

Choose a reason for hiding this comment

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

In IRB, configs[:default] is used for all character output except the completion dialog.
Actually, :enhanced and :scrollbar are not used.
I was also unsure whether to keep them or not, but even if they were there, IRB wouldn't malfunction so I left it. But should they be deleted?

Copy link
Member

Choose a reason for hiding this comment

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

It looks like IRB's document dialog (which does not specify face yet) use it.

Copy link
Member

@ima1zumi ima1zumi Nov 6, 2023

Choose a reason for hiding this comment

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

Thanks for letting me know.
Does it mean that a default value is used if the face argument is not provided in Reline::DialogRenderInfo.new?

Like this code https://github.com/ruby/irb/blob/v1.8.3/lib/irb/input-method.rb#L382

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

https://github.com/ruby/reline/pull/552/files#diff-082d93e1b70331eead4465512d8e0f47b9a91734b7c899d5929168c620cf8025R65-R67

As a result of ensuring that the absence of :enhanced and :scrollbar attributes are not broken even if the user forgets the scrollbar attribute in the completion_dialog config, enhanced and scrollbar attributes are automatically created in the :default config, too.
This is kind of a compromise with the existing implementation, where the concept of "completion_dialog" basically belongs to the IRB, but the SGR settings are set on the Reline side.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Sorry, I overlooked tompng's comment.
default config is used here https://github.com/ruby/reline/pull/552/files#diff-9703d9141e08b96c2d616930b207873b52dc9eb68b81223818fe250cdb0e927fR834

Totally I made confusing this thread, lol

Copy link
Member

Choose a reason for hiding this comment

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

Thank you! I understood.

Co-authored-by: ima1zumi <52617472+ima1zumi@users.noreply.github.com>
Copy link
Member

@st0012 st0012 left a comment

Choose a reason for hiding this comment

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

Thank you for leading this effort! I can't wait to customise my IRB with it 🙌

(Reminder: given the number of commits, please use squash merge or squash commits with rebase before merging. Otherwise it could break ruby/ruby's syncing script)

Copy link
Member

@ima1zumi ima1zumi left a comment

Choose a reason for hiding this comment

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

🚀

@hasumikin hasumikin merged commit fdc1d3b into ruby:master Nov 6, 2023
30 checks passed
matzbot pushed a commit to ruby/ruby that referenced this pull request Nov 6, 2023
character attributes
(ruby/reline#552)

* Reine::Face

* fix test_yamatanooroti

* Define singleton methods to make accessors to attributes of a face

* s/display/foreground/

* s/default/default_style/ && s/normal_line/default/ && s/enhanced_line/enhanced/

* fix typo

* FaceConfig.new now takes keyword arguments

* Update lib/reline/face.rb

Co-authored-by: Stan Lo <stan001212@gmail.com>

* Update test/reline/test_face.rb

Co-authored-by: Stan Lo <stan001212@gmail.com>

* Fix to correspond to frozen_string_literal

* Face::FaceConfig -> Face::Config

* ref ruby/reline#552 (review)

* delete unused ivar

* ref ruby/reline#552 (comment)

* insert "\e[0m" into all SGR

* tiny fix

* ESSENTIAL_DEFINE_NAMES

ref ruby/reline#552 (comment)

* Change to Hash-accessor style

- Reline::Face[:completion_dialog].enhanced ->
  Reline::Face[:completion_dialog][:enhanced]
- Reline::Face.configs shows all defined values

* Cache array method call in local variable

* Tests for Face configuration variations

* resolve ruby/reline#552 (review)

* amend  to

* check invalid SGR parameter in :style

* The order of define values should be preserved

* Update test/reline/test_face.rb

Co-authored-by: Stan Lo <stan001212@gmail.com>

* Update test/reline/test_face.rb

Co-authored-by: Stan Lo <stan001212@gmail.com>

* Add methods: load_initial_config and reset_to_initial_config. And teardown in tests

* omission in amending "style: :default" to "style: :reset"

* refs ruby/reline#598

* Fix link

* amend method name

* Update lib/reline/face.rb

Co-authored-by: ima1zumi <52617472+ima1zumi@users.noreply.github.com>

---------

ruby/reline@fdc1d3b1e5

Co-authored-by: Stan Lo <stan001212@gmail.com>
Co-authored-by: ima1zumi <52617472+ima1zumi@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Development

Successfully merging this pull request may close these issues.

None yet

6 participants