diff --git a/src/tests/fixtures/grid_copy_wrapped b/src/tests/fixtures/grid_copy_wrapped
new file mode 100755
index 000000000..f46d7dffe
--- /dev/null
+++ b/src/tests/fixtures/grid_copy_wrapped
@@ -0,0 +1,10 @@
+Welcome to fish, the friendly interactive shell
+Type `help` for instructions on how to use fish
+[?2004h]0;fish /home/thomas/Projects/zellij[30m(B[m
[K[J[K
+[1;36mzellij[0m on [1;35m main[0m [1;31m[$!?][0m is [1;38;5;208m📦 v0.25.0[0m via [1;31m🦀 v1.58.1 [0m
+[1;32m❯[0m [K
[C[C

[C[Cc[J
[3C[38;2;255;0;0mc
[3C[30m(B[m[38;2;85;85;85margo make run --debug
[3C[30m(B[m[38;2;255;0;0ma[38;2;85;85;85mrgo make run --debug
[4C[30m(B[m[38;2;255;0;0mt[30m(B[m[K
[5C[38;2;0;95;215mcat
[5C[30m(B[m[38;2;85;85;85m lorem.txt
[5C[30m(B[m[38;2;0;95;215m lorem.txt
[15C[30m(B[m[10D [38;2;0;175;255m[4mlorem.txt
[15C[30m(B[m
[15C
+[30m(B[m[?2004l]0;cat lorem.txt /home/thomas/Projects/zellij[30m(B[m
Lorem ipsum dolor sit amet,                                                                                                                          consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
+[2m⏎(B[m                                                                        
⏎ 
[K[?2004h]0;fish /home/thomas/Projects/zellij[30m(B[m[K[J[K
+[1;36mzellij[0m on [1;35m main[0m [1;31m[$!?][0m is [1;38;5;208m📦 v0.25.0[0m via [1;31m🦀 v1.58.1 [0m
+[1;32m❯[0m [K
[C[C
+[30m(B[m[30m(B[m[?2004l
\ No newline at end of file
diff --git a/zellij-server/src/panes/grid.rs b/zellij-server/src/panes/grid.rs
index 11a77bfd9..b524c69b6 100644
--- a/zellij-server/src/panes/grid.rs
+++ b/zellij-server/src/panes/grid.rs
@@ -1291,27 +1291,27 @@ impl Grid {
         self.preceding_char = Some(terminal_character);
     }
     pub fn start_selection(&mut self, start: &Position) {
-        let old_selection = self.selection.clone();
+        let old_selection = self.selection;
         self.selection.start(*start);
         self.update_selected_lines(&old_selection, &self.selection.clone());
         self.mark_for_rerender();
     }
     pub fn update_selection(&mut self, to: &Position) {
-        let old_selection = self.selection.clone();
+        let old_selection = self.selection;
         self.selection.to(*to);
         self.update_selected_lines(&old_selection, &self.selection.clone());
         self.mark_for_rerender();
     }
 
     pub fn end_selection(&mut self, end: Option<&Position>) {
-        let old_selection = self.selection.clone();
+        let old_selection = self.selection;
         self.selection.end(end);
         self.update_selected_lines(&old_selection, &self.selection.clone());
         self.mark_for_rerender();
     }
 
     pub fn reset_selection(&mut self) {
-        let old_selection = self.selection.clone();
+        let old_selection = self.selection;
         self.selection.reset();
         self.update_selected_lines(&old_selection, &self.selection.clone());
         self.mark_for_rerender();
@@ -1366,25 +1366,31 @@ impl Grid {
                 continue;
             };
 
-            let excess_width = row.excess_width();
-            let mut line: Vec<TerminalCharacter> = row.columns.iter().copied().collect();
-            // pad line
-            line.resize(
-                self.width.saturating_sub(excess_width),
-                EMPTY_TERMINAL_CHARACTER,
-            );
-
             let mut terminal_col = 0;
-            for terminal_character in line {
+            for terminal_character in &row.columns {
                 if (start_column..end_column).contains(&terminal_col) {
                     line_selection.push(terminal_character.character);
                 }
 
                 terminal_col += terminal_character.width;
             }
-            selection.push(String::from(line_selection.trim_end()));
+
+            if row.is_canonical {
+                selection.push(line_selection);
+            } else {
+                // rejoin wrapped lines if possible
+                match selection.last_mut() {
+                    Some(previous_line) => previous_line.push_str(&line_selection),
+                    None => selection.push(line_selection),
+                }
+            }
         }
 
+        // TODO: distinguish whitespace that was output explicitly vs implicitly (e.g add_newline)
+        // for example: echo "     " vs empty lines
+        // for now trim after building the selection to handle whitespace in wrapped lines
+        let selection: Vec<_> = selection.iter().map(|l| l.trim_end()).collect();
+
         Some(selection.join("\n"))
     }
 
diff --git a/zellij-server/src/panes/unit/grid_tests.rs b/zellij-server/src/panes/unit/grid_tests.rs
index 9586352e0..72b1f5578 100644
--- a/zellij-server/src/panes/unit/grid_tests.rs
+++ b/zellij-server/src/panes/unit/grid_tests.rs
@@ -859,6 +859,30 @@ fn copy_selected_text_from_viewport() {
     );
 }
 
+#[test]
+fn copy_wrapped_selected_text_from_viewport() {
+    let mut vte_parser = vte::Parser::new();
+    let mut grid = Grid::new(
+        22,
+        73,
+        Palette::default(),
+        Rc::new(RefCell::new(LinkHandler::new())),
+    );
+    let fixture_name = "grid_copy_wrapped";
+    let content = read_fixture(fixture_name);
+    for byte in content {
+        vte_parser.advance(&mut grid, byte);
+    }
+
+    grid.start_selection(&Position::new(5, 0));
+    grid.end_selection(Some(&Position::new(8, 42)));
+    let text = grid.get_selected_text();
+    assert_eq!(
+        text.unwrap(),
+        "Lorem ipsum dolor sit amet,                                                                                                                          consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua."
+    );
+}
+
 #[test]
 fn copy_selected_text_from_lines_above() {
     let mut vte_parser = vte::Parser::new();
