Repository: alacritty/alacritty (language: rust)

Issue:
Spurious char from previous line in double click selection
Since alacritty `0.13.0` selecting a word / line with a double click will also select the last character of the previous line if it is non-whitespace.


![image](https://github.com/alacritty/alacritty/assets/1280142/098351c6-5b78-4838-ac40-0231990f7cf5)
(double click on `bbb` will select `X\nbbb`)

![image](https://github.com/alacritty/alacritty/assets/1280142/727b7dba-e0da-4192-bbdf-399953ff24df)
(double click on `bbb` will correctly select `bbb`)

This is especially annoying for shell configs that print the date / command duration at the end of the previous line and took me a while to figure out where these spurious char was coming from.

### System

OS: Arch Linux
Version: `0.13.0` and `0.13.1 (fe2a3c56)` (affected)
Linux/BSD: sway (Wayland)

### Logs

```
[0.000000647s] [INFO ] [alacritty] Welcome to Alacritty
[0.000027276s] [INFO ] [alacritty] Version 0.13.1 (fe2a3c56)
[0.000030789s] [INFO ] [alacritty] Running on Wayland
[0.000284642s] [INFO ] [alacritty] Configuration files loaded from:
                                     "/home/user/.config/alacritty/alacritty.toml"
                                     ".config/alacritty/themes/iterm-black-bg.toml"
[0.020153768s] [INFO ] [alacritty] Using EGL 1.5
[0.020188141s] [DEBUG] [alacritty] Picked GL Config:
                                     buffer_type: Some(Rgb { r_size: 8, g_size: 8, b_size: 8 })
                                     alpha_size: 8
                                     num_samples: 0
                                     hardware_accelerated: true
                                     supports_transparency: Some(true)
                                     config_api: Api(OPENGL | GLES1 | GLES2 | GLES3)
                                     srgb_capable: true
[0.022885544s] [INFO ] [alacritty] Window scale factor: 1
[0.023746219s] [DEBUG] [alacritty] Loading "Hack" font
[0.031184536s] [DEBUG] [crossfont] Loaded Face Face { ft_face: Font Face: Regular, load_flags: TARGET_LIGHT, render_mode: "Lcd", lcd_filter: 1 }
[0.033490671s] [DEBUG] [crossfont] Loaded Face Face { ft_face: Font Face: Bold, load_flags: TARGET_LIGHT, render_mode: "Lcd", lcd_filter: 1 }
[0.035980153s] [DEBUG] [crossfont] Loaded Face Face { ft_face: Font Face: Italic, load_flags: TARGET_LIGHT, render_mode: "Lcd", lcd_filter: 1 }
[0.038732463s] [DEBUG] [crossfont] Loaded Face Face { ft_face: Font Face: Bold Italic, load_flags: TARGET_LIGHT, render_mode: "Lcd", lcd_filter: 1 }
[0.041431187s] [INFO ] [alacritty] Running on Mesa Intel(R) Xe Graphics (TGL GT2)
[0.041440256s] [INFO ] [alacritty] OpenGL version 4.6 (Core Profile) Mesa 23.3.2-arch1.2, shader_version 4.60
[0.041445048s] [INFO ] [alacritty] Using OpenGL 3.3 renderer
[0.045855281s] [DEBUG] [alacritty] Enabled debug logging for OpenGL
[0.045991480s] [DEBUG] [alacritty] Filling glyph cache with common glyphs
[0.054647581s] [INFO ] [alacritty] Cell size: 10 x 19
[0.054672523s] [INFO ] [alacritty] Padding: 0 x 0
[0.054676411s] [INFO ] [alacritty] Width: 800, Height: 600
[0.054709278s] [INFO ] [alacritty] PTY dimensions: 31 x 80
[0.057172494s] [INFO ] [alacritty] Initialisation complete
[0.058873356s] [DEBUG] [alacritty_terminal] New num_cols is 239 and num_lines is 23
[0.058954826s] [INFO ] [alacritty] Padding: 0 x 0
[0.058959145s] [INFO ] [alacritty] Width: 2396, Height: 439
[0.099895515s] [DEBUG] [crossfont] Loaded Face Face { ft_face: Font Face: Regular, load_flags: TARGET_LIGHT, render_mode: "Lcd", lcd_filter: 1 }
[0.102891420s] [DEBUG] [crossfont] Loaded Face Face { ft_face: Font Face: Bold, load_flags: TARGET_LIGHT, render_mode: "Lcd", lcd_filter: 1 }
[0.106041474s] [DEBUG] [crossfont] Loaded Face Face { ft_face: Font Face: Italic, load_flags: TARGET_LIGHT, render_mode: "Lcd", lcd_filter: 1 }
[0.108768348s] [DEBUG] [crossfont] Loaded Face Face { ft_face: Font Face: Bold Italic, load_flags: TARGET_LIGHT, render_mode: "Lcd", lcd_filter: 1 }
[0.110237303s] [INFO ] [alacritty] Font size changed to 32.0 px
[0.110254513s] [INFO ] [alacritty] Cell size: 19 x 38
[0.110264506s] [DEBUG] [alacritty_terminal] New num_cols is 252 and num_lines is 23
[0.116651914s] [INFO ] [alacritty] Padding: 0 x 0
[0.116671044s] [INFO ] [alacritty] Width: 4792, Height: 878
[2.320997216s] [INFO ] [alacritty] Goodbye
```
(log of a different window)


Discussion / hints:
Seems like somehow 845a5d8a8d47c233c4ed8177ecbb20b05b22118b broke this.

Fix patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index aa27a8c128b..01514ddeaf0 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -7,6 +7,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
 
 ## 0.14.0-dev
 
+### Fixed
+
+- Vi inline search/semantic selection expanding across newlines
+
 ## 0.13.1
 
 ### Added
diff --git a/alacritty_terminal/src/term/search.rs b/alacritty_terminal/src/term/search.rs
index 9e900b8ab3f..585e191c0fa 100644
--- a/alacritty_terminal/src/term/search.rs
+++ b/alacritty_terminal/src/term/search.rs
@@ -540,15 +540,15 @@ impl<T> Term<T> {
 
         let wide = Flags::WIDE_CHAR | 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;
+            }
+
             point = cell.point;
 
             if !cell.flags.intersects(wide) && needles.contains(cell.c) {
                 return Ok(point);
             }
-
-            if point.column == last_column && !cell.flags.contains(Flags::WRAPLINE) {
-                break;
-            }
         }
 
         Err(point)
@@ -562,6 +562,11 @@ impl<T> Term<T> {
         let wide = Flags::WIDE_CHAR | Flags::WIDE_CHAR_SPACER | Flags::LEADING_WIDE_CHAR_SPACER;
         let last_column = self.columns() - 1;
 
+        // Immediately stop if start point in on line break.
+        if point.column == last_column && !self.grid[point].flags.contains(Flags::WRAPLINE) {
+            return Err(point);
+        }
+
         for cell in self.grid.iter_from(point) {
             point = cell.point;
 
@@ -1129,4 +1134,25 @@ mod tests {
         let end = Point::new(Line(0), Column(3));
         assert_eq!(term.regex_search_right(&mut regex, start, end), Some(start..=end));
     }
+
+    #[test]
+    fn newline_breaking_semantic() {
+        #[rustfmt::skip]
+        let term = mock_term("\
+            test abc\r\n\
+            def test\
+        ");
+
+        // Start at last character.
+        let start = term.semantic_search_left(Point::new(Line(0), Column(7)));
+        let end = term.semantic_search_right(Point::new(Line(0), Column(7)));
+        assert_eq!(start, Point::new(Line(0), Column(5)));
+        assert_eq!(end, Point::new(Line(0), Column(7)));
+
+        // Start at first character.
+        let start = term.semantic_search_left(Point::new(Line(1), Column(0)));
+        let end = term.semantic_search_right(Point::new(Line(1), Column(0)));
+        assert_eq!(start, Point::new(Line(1), Column(0)));
+        assert_eq!(end, Point::new(Line(1), Column(2)));
+    }
 }


Test patch: