Repository: alacritty/alacritty (language: rust)

Issue:
alacritty not honouring [semantic_escape_chars] setting 
I hope I am not over-stepping any github/alacritty rules. My previous ticket has been closed, and I cannot find a way to reopen it (just joined yesterday).

Please feel free to delete this ticket if need be.

`semantic_escape_chars = ",│`|:\"' ()[]{}<>\t•-—－．"`

Here's a video of what happens after [Ctrl] + [Shift] + [Space]

https://github.com/user-attachments/assets/0657d09d-544f-46e6-8964-1e58f977de26




Discussion / hints:
You can just comment under existing issues, there's no need to create new ones.

I've checked out the characters you mention specifically and it seems like fullwidth characters can't be used as semantic escape chars. 
Thanks for clearing that up. Many thanks for an exceptional piece of software. 

Fix patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 38584ca5d06..946f48ea7a8 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -38,6 +38,7 @@ Notable changes to the `alacritty_terminal` crate are documented in its
 - Broken search with words broken across line boundary on the first character
 - Config import changes not being live reloaded
 - Cursor color requests with default cursor colors
+- Fullwidth semantic escape characters
 
 ## 0.13.2
 
diff --git a/alacritty_terminal/src/term/search.rs b/alacritty_terminal/src/term/search.rs
index a5ae9337a96..33f6ee056b5 100644
--- a/alacritty_terminal/src/term/search.rs
+++ b/alacritty_terminal/src/term/search.rs
@@ -516,7 +516,14 @@ impl<T> Term<T> {
     #[must_use]
     pub fn semantic_search_left(&self, point: Point) -> Point {
         match self.inline_search_left(point, self.semantic_escape_chars()) {
-            Ok(point) => self.grid.iter_from(point).next().map_or(point, |cell| cell.point),
+            // If we found a match, reverse for at least one cell, skipping over wide cell spacers.
+            Ok(point) => {
+                let wide_spacer = Flags::WIDE_CHAR_SPACER | Flags::LEADING_WIDE_CHAR_SPACER;
+                self.grid
+                    .iter_from(point)
+                    .find(|cell| !cell.flags.intersects(wide_spacer))
+                    .map_or(point, |cell| cell.point)
+            },
             Err(point) => point,
         }
     }
@@ -538,7 +545,7 @@ impl<T> Term<T> {
         let mut iter = self.grid.iter_from(point);
         let last_column = self.columns() - 1;
 
-        let wide = Flags::WIDE_CHAR | Flags::WIDE_CHAR_SPACER | Flags::LEADING_WIDE_CHAR_SPACER;
+        let wide_spacer = Flags::WIDE_CHAR_SPACER | Flags::LEADING_WIDE_CHAR_SPACER;
         while let Some(cell) = iter.prev() {
             if cell.point.column == last_column && !cell.flags.contains(Flags::WRAPLINE) {
                 break;
@@ -546,7 +553,7 @@ impl<T> Term<T> {
 
             point = cell.point;
 
-            if !cell.flags.intersects(wide) && needles.contains(cell.c) {
+            if !cell.flags.intersects(wide_spacer) && needles.contains(cell.c) {
                 return Ok(point);
             }
         }
@@ -559,7 +566,7 @@ impl<T> Term<T> {
         // Limit the starting point to the last line in the history
         point.line = max(point.line, self.topmost_line());
 
-        let wide = Flags::WIDE_CHAR | Flags::WIDE_CHAR_SPACER | Flags::LEADING_WIDE_CHAR_SPACER;
+        let wide_spacer = Flags::WIDE_CHAR_SPACER | Flags::LEADING_WIDE_CHAR_SPACER;
         let last_column = self.columns() - 1;
 
         // Immediately stop if start point in on line break.
@@ -570,7 +577,7 @@ impl<T> Term<T> {
         for cell in self.grid.iter_from(point) {
             point = cell.point;
 
-            if !cell.flags.intersects(wide) && needles.contains(cell.c) {
+            if !cell.flags.intersects(wide_spacer) && needles.contains(cell.c) {
                 return Ok(point);
             }
 
@@ -1171,4 +1178,16 @@ mod tests {
         let match_end = Point::new(Line(1), Column(2));
         assert_eq!(term.regex_search_left(&mut regex, start, end), Some(match_start..=match_end));
     }
+
+    #[test]
+    fn fullwidth_semantic() {
+        #[rustfmt::skip]
+        let mut term = mock_term("test－x－test");
+        term.config.semantic_escape_chars = "－".into();
+
+        let start = term.semantic_search_left(Point::new(Line(0), Column(6)));
+        let end = term.semantic_search_right(Point::new(Line(0), Column(6)));
+        assert_eq!(start, Point::new(Line(0), Column(6)));
+        assert_eq!(end, Point::new(Line(0), Column(6)));
+    }
 }


Test patch: