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

Support DECRQM 2027 - grapheme cluster processing #4320

Closed
rockorager opened this issue Sep 20, 2023 · 5 comments
Closed

Support DECRQM 2027 - grapheme cluster processing #4320

rockorager opened this issue Sep 20, 2023 · 5 comments
Labels
enhancement New feature or request fixed-in-nightly This is (or is assumed to be) fixed in the nightly builds.

Comments

@rockorager
Copy link

Is your feature request related to a problem? Please describe.
Determining how a terminal will move the cursor when printing a complex unicode grapheme is a difficult chore. Wezterm is one of a handful of terminals (contour, foot being the others) that properly moves the cursor according to Unicode specifications.

Describe the solution you'd like
The author of Contour has created a specification for this mode of rendering: terminal-unicode-core, implemented as a private DEC mode 2027. I think wezterm can accurately respond to DECRQM queries with a 3 (permanently enabled). It would be a bonus to be able to set/reset the mode using DECSET and DECRST but at least I would like to see a response to DECRQM so I can know what will happen.

Describe alternatives you've considered
At application start, I query cursor position, print a complex emoji, and query cursor position again to determine support for grapheme processing. This is not ideal.

Additional context
I've tested several terminals for proper unicode support. foot, contour, and wezterm are the only three that support proper processing. contour supports 2027, and foot has just opened a PR this morning to add support. It would be awesome to have all three respond to this query!

@wez
Copy link
Owner

wez commented Sep 20, 2023

Seems interesting!
I filed contour-terminal/terminal-unicode-core#2 to get a more easily viewable version of the spec in that repo

@wez
Copy link
Owner

wez commented Sep 20, 2023

diff --git a/term/src/terminalstate/mod.rs b/term/src/terminalstate/mod.rs
index d7a1fab2c..fc12cc005 100644
--- a/term/src/terminalstate/mod.rs
+++ b/term/src/terminalstate/mod.rs
@@ -1345,6 +1345,22 @@ impl TerminalState {
         }
     }

+    /// Indicates that mode is permanently enabled
+    fn decqrm_response_permanent(&mut self, mode: Mode) {
+        let (is_dec, number) = match &mode {
+            Mode::QueryDecPrivateMode(DecPrivateMode::Code(code)) => (true, code.to_u16().unwrap()),
+            Mode::QueryDecPrivateMode(DecPrivateMode::Unspecified(code)) => (true, *code),
+            Mode::QueryMode(TerminalMode::Code(code)) => (false, code.to_u16().unwrap()),
+            Mode::QueryMode(TerminalMode::Unspecified(code)) => (false, *code),
+            _ => unreachable!(),
+        };
+
+        let prefix = if is_dec { "?" } else { "" };
+
+        write!(self.writer, "\x1b[{prefix}{number};3$y").ok();
+        self.writer.flush().ok();
+    }
+
     fn decqrm_response(&mut self, mode: Mode, mut recognized: bool, enabled: bool) {
         let (is_dec, number) = match &mode {
             Mode::QueryDecPrivateMode(DecPrivateMode::Code(code)) => (true, code.to_u16().unwrap()),
@@ -1449,6 +1465,21 @@ impl TerminalState {
                 self.decqrm_response(mode, true, self.left_and_right_margin_mode);
             }

+            Mode::SetDecPrivateMode(DecPrivateMode::Code(
+                DecPrivateModeCode::GraphemeClustering,
+            ))
+            | Mode::ResetDecPrivateMode(DecPrivateMode::Code(
+                DecPrivateModeCode::GraphemeClustering,
+            )) => {
+                // Permanently enabled
+            }
+
+            Mode::QueryDecPrivateMode(DecPrivateMode::Code(
+                DecPrivateModeCode::GraphemeClustering,
+            )) => {
+                self.decqrm_response_permanent(mode);
+            }
+
             Mode::SetDecPrivateMode(DecPrivateMode::Code(DecPrivateModeCode::SaveCursor)) => {
                 self.dec_save_cursor();
             }
diff --git a/termwiz/src/escape/csi.rs b/termwiz/src/escape/csi.rs
index fe7a2cee7..810f99f1f 100644
--- a/termwiz/src/escape/csi.rs
+++ b/termwiz/src/escape/csi.rs
@@ -841,6 +841,11 @@ pub enum DecPrivateModeCode {
     EnableAlternateScreen = 47,
     OptEnableAlternateScreen = 1047,
     BracketedPaste = 2004,
+
+    /// <https://github.com/contour-terminal/terminal-unicode-core/>
+    /// Grapheme clustering mode
+    GraphemeClustering = 2027,
+
     /// Applies to sixel and regis modes
     UsePrivateColorRegistersForEachGraphic = 1070,

Could you try this diff and let me know if that does the job?
This should be sufficient to respond to that query. I haven't done any testing beyond verifying that it compiles.

@rockorager
Copy link
Author

Works great! Got CSI ? 2027 ; 3 y from my query, as expected. Thanks!

@wez wez closed this as completed in 33e727b Sep 20, 2023
@wez
Copy link
Owner

wez commented Sep 20, 2023

Thanks! This is now in main and will show up in nightly builds within the next hour or so.

@wez wez added the fixed-in-nightly This is (or is assumed to be) fixed in the nightly builds. label Sep 20, 2023
@github-actions
Copy link
Contributor

I'm going to lock this issue because it has been closed for 30 days ⏳. This helps our maintainers find and focus on the active issues. If you have found a problem that seems similar to this, please open a new issue and complete the issue template so we can capture all the details necessary to investigate further.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Oct 21, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
enhancement New feature or request fixed-in-nightly This is (or is assumed to be) fixed in the nightly builds.
Projects
None yet
Development

No branches or pull requests

2 participants