diff --git a/helix-view/src/base64.rs b/helix-view/src/base64.rs
new file mode 100644
index 00000000..a0dc167f
--- /dev/null
+++ b/helix-view/src/base64.rs
@@ -0,0 +1,163 @@
+// A minimal base64 implementation to keep from pulling in a crate for just that. It's based on
+// https://github.com/marshallpierce/rust-base64 but without all the customization options.
+// The biggest portion comes from
+// https://github.com/marshallpierce/rust-base64/blob/a675443d327e175f735a37f574de803d6a332591/src/engine/naive.rs#L42
+// Thanks, rust-base64!
+
+// The MIT License (MIT)
+
+// Copyright (c) 2015 Alice Maz
+
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+use std::ops::{BitAnd, BitOr, Shl, Shr};
+
+const PAD_BYTE: u8 = b'=';
+const ENCODE_TABLE: &[u8] =
+    "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".as_bytes();
+const LOW_SIX_BITS: u32 = 0x3F;
+
+pub fn encode(input: &[u8]) -> String {
+    let rem = input.len() % 3;
+    let complete_chunks = input.len() / 3;
+    let remainder_chunk = if rem == 0 { 0 } else { 1 };
+    let encoded_size = (complete_chunks + remainder_chunk) * 4;
+
+    let mut output = vec![0; encoded_size];
+
+    // complete chunks first
+    let complete_chunk_len = input.len() - rem;
+
+    let mut input_index = 0_usize;
+    let mut output_index = 0_usize;
+    while input_index < complete_chunk_len {
+        let chunk = &input[input_index..input_index + 3];
+
+        // populate low 24 bits from 3 bytes
+        let chunk_int: u32 =
+            (chunk[0] as u32).shl(16) | (chunk[1] as u32).shl(8) | (chunk[2] as u32);
+        // encode 4x 6-bit output bytes
+        output[output_index] = ENCODE_TABLE[chunk_int.shr(18) as usize];
+        output[output_index + 1] = ENCODE_TABLE[chunk_int.shr(12_u8).bitand(LOW_SIX_BITS) as usize];
+        output[output_index + 2] = ENCODE_TABLE[chunk_int.shr(6_u8).bitand(LOW_SIX_BITS) as usize];
+        output[output_index + 3] = ENCODE_TABLE[chunk_int.bitand(LOW_SIX_BITS) as usize];
+
+        input_index += 3;
+        output_index += 4;
+    }
+
+    // then leftovers
+    if rem == 2 {
+        let chunk = &input[input_index..input_index + 2];
+
+        // high six bits of chunk[0]
+        output[output_index] = ENCODE_TABLE[chunk[0].shr(2) as usize];
+        // bottom 2 bits of [0], high 4 bits of [1]
+        output[output_index + 1] = ENCODE_TABLE
+            [(chunk[0].shl(4_u8).bitor(chunk[1].shr(4_u8)) as u32).bitand(LOW_SIX_BITS) as usize];
+        // bottom 4 bits of [1], with the 2 bottom bits as zero
+        output[output_index + 2] =
+            ENCODE_TABLE[(chunk[1].shl(2_u8) as u32).bitand(LOW_SIX_BITS) as usize];
+        output[output_index + 3] = PAD_BYTE;
+    } else if rem == 1 {
+        let byte = input[input_index];
+        output[output_index] = ENCODE_TABLE[byte.shr(2) as usize];
+        output[output_index + 1] =
+            ENCODE_TABLE[(byte.shl(4_u8) as u32).bitand(LOW_SIX_BITS) as usize];
+        output[output_index + 2] = PAD_BYTE;
+        output[output_index + 3] = PAD_BYTE;
+    }
+    String::from_utf8(output).expect("Invalid UTF8")
+}
+
+#[cfg(test)]
+mod tests {
+    fn compare_encode(expected: &str, target: &[u8]) {
+        assert_eq!(expected, super::encode(target));
+    }
+
+    #[test]
+    fn encode_rfc4648_0() {
+        compare_encode("", b"");
+    }
+
+    #[test]
+    fn encode_rfc4648_1() {
+        compare_encode("Zg==", b"f");
+    }
+
+    #[test]
+    fn encode_rfc4648_2() {
+        compare_encode("Zm8=", b"fo");
+    }
+
+    #[test]
+    fn encode_rfc4648_3() {
+        compare_encode("Zm9v", b"foo");
+    }
+
+    #[test]
+    fn encode_rfc4648_4() {
+        compare_encode("Zm9vYg==", b"foob");
+    }
+
+    #[test]
+    fn encode_rfc4648_5() {
+        compare_encode("Zm9vYmE=", b"fooba");
+    }
+
+    #[test]
+    fn encode_rfc4648_6() {
+        compare_encode("Zm9vYmFy", b"foobar");
+    }
+
+    #[test]
+    fn encode_all_ascii() {
+        let mut ascii = Vec::<u8>::with_capacity(128);
+
+        for i in 0..128 {
+            ascii.push(i);
+        }
+
+        compare_encode(
+            "AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7P\
+         D0+P0BBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWltcXV5fYGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6e3x9fn8\
+         =",
+            &ascii,
+        );
+    }
+
+    #[test]
+    fn encode_all_bytes() {
+        let mut bytes = Vec::<u8>::with_capacity(256);
+
+        for i in 0..255 {
+            bytes.push(i);
+        }
+        bytes.push(255); //bug with "overflowing" ranges?
+
+        compare_encode(
+            "AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7P\
+         D0+P0BBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWltcXV5fYGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6e3x9fn\
+         +AgYKDhIWGh4iJiouMjY6PkJGSk5SVlpeYmZqbnJ2en6ChoqOkpaanqKmqq6ytrq+wsbKztLW2t7i5uru8vb6\
+         /wMHCw8TFxsfIycrLzM3Oz9DR0tPU1dbX2Nna29zd3t/g4eLj5OXm5+jp6uvs7e7v8PHy8/T19vf4+fr7/P3+/w==",
+            &bytes,
+        );
+    }
+}
diff --git a/helix-view/src/clipboard.rs b/helix-view/src/clipboard.rs
index ad6f621a..19fade69 100644
--- a/helix-view/src/clipboard.rs
+++ b/helix-view/src/clipboard.rs
@@ -3,6 +3,7 @@
 use anyhow::Result;
 use std::borrow::Cow;
 
+#[derive(Clone, Copy, Debug)]
 pub enum ClipboardType {
     Clipboard,
     Selection,
@@ -72,45 +73,48 @@ pub fn get_clipboard_provider() -> Box<dyn ClipboardProvider> {
 
 #[cfg(target_os = "macos")]
 pub fn get_clipboard_provider() -> Box<dyn ClipboardProvider> {
-    use provider::command::exists;
+    use crate::env::binary_exists;
 
-    if exists("pbcopy") && exists("pbpaste") {
+    if binary_exists("pbcopy") && binary_exists("pbpaste") {
         command_provider! {
             paste => "pbpaste";
             copy => "pbcopy";
         }
     } else {
-        Box::new(provider::NopProvider::new())
+        Box::new(provider::FallbackProvider::new())
     }
 }
 
 #[cfg(target_os = "wasm32")]
 pub fn get_clipboard_provider() -> Box<dyn ClipboardProvider> {
     // TODO:
-    Box::new(provider::NopProvider::new())
+    Box::new(provider::FallbackProvider::new())
 }
 
 #[cfg(not(any(windows, target_os = "wasm32", target_os = "macos")))]
 pub fn get_clipboard_provider() -> Box<dyn ClipboardProvider> {
-    use provider::command::{env_var_is_set, exists, is_exit_success};
+    use crate::env::{binary_exists, env_var_is_set};
+    use provider::command::is_exit_success;
     // TODO: support for user-defined provider, probably when we have plugin support by setting a
     // variable?
 
-    if env_var_is_set("WAYLAND_DISPLAY") && exists("wl-copy") && exists("wl-paste") {
+    if env_var_is_set("WAYLAND_DISPLAY") && binary_exists("wl-copy") && binary_exists("wl-paste") {
         command_provider! {
             paste => "wl-paste", "--no-newline";
             copy => "wl-copy", "--type", "text/plain";
             primary_paste => "wl-paste", "-p", "--no-newline";
             primary_copy => "wl-copy", "-p", "--type", "text/plain";
         }
-    } else if env_var_is_set("DISPLAY") && exists("xclip") {
+    } else if env_var_is_set("DISPLAY") && binary_exists("xclip") {
         command_provider! {
             paste => "xclip", "-o", "-selection", "clipboard";
             copy => "xclip", "-i", "-selection", "clipboard";
             primary_paste => "xclip", "-o";
             primary_copy => "xclip", "-i";
         }
-    } else if env_var_is_set("DISPLAY") && exists("xsel") && is_exit_success("xsel", &["-o", "-b"])
+    } else if env_var_is_set("DISPLAY")
+        && binary_exists("xsel")
+        && is_exit_success("xsel", &["-o", "-b"])
     {
         // FIXME: check performance of is_exit_success
         command_provider! {
@@ -119,43 +123,78 @@ pub fn get_clipboard_provider() -> Box<dyn ClipboardProvider> {
             primary_paste => "xsel", "-o";
             primary_copy => "xsel", "-i";
         }
-    } else if exists("win32yank.exe") {
+    } else if binary_exists("win32yank.exe") {
         command_provider! {
             paste => "win32yank.exe", "-o", "--lf";
             copy => "win32yank.exe", "-i", "--crlf";
         }
-    } else if exists("termux-clipboard-set") && exists("termux-clipboard-get") {
+    } else if binary_exists("termux-clipboard-set") && binary_exists("termux-clipboard-get") {
         command_provider! {
             paste => "termux-clipboard-get";
             copy => "termux-clipboard-set";
         }
-    } else if env_var_is_set("TMUX") && exists("tmux") {
+    } else if env_var_is_set("TMUX") && binary_exists("tmux") {
         command_provider! {
             paste => "tmux", "save-buffer", "-";
             copy => "tmux", "load-buffer", "-";
         }
     } else {
-        Box::new(provider::NopProvider::new())
+        Box::new(provider::FallbackProvider::new())
     }
 }
 
+#[cfg(not(target_os = "windows"))]
 pub mod provider {
     use super::{ClipboardProvider, ClipboardType};
     use anyhow::Result;
     use std::borrow::Cow;
 
-    #[cfg(not(target_os = "windows"))]
+    #[cfg(feature = "term")]
+    mod osc52 {
+        use {super::ClipboardType, crate::base64, crossterm};
+
+        #[derive(Debug)]
+        pub struct SetClipboardCommand {
+            encoded_content: String,
+            clipboard_type: ClipboardType,
+        }
+
+        impl SetClipboardCommand {
+            pub fn new(content: &str, clipboard_type: ClipboardType) -> Self {
+                Self {
+                    encoded_content: base64::encode(content.as_bytes()),
+                    clipboard_type,
+                }
+            }
+        }
+
+        impl crossterm::Command for SetClipboardCommand {
+            fn write_ansi(&self, f: &mut impl std::fmt::Write) -> std::fmt::Result {
+                let kind = match &self.clipboard_type {
+                    ClipboardType::Clipboard => "c",
+                    ClipboardType::Selection => "p",
+                };
+                // Send an OSC 52 set command: https://terminalguide.namepad.de/seq/osc-52/
+                write!(f, "\x1b]52;{};{}\x1b\\", kind, &self.encoded_content)
+            }
+        }
+    }
+
     #[derive(Debug)]
-    pub struct NopProvider {
+    pub struct FallbackProvider {
         buf: String,
         primary_buf: String,
     }
 
-    #[cfg(not(target_os = "windows"))]
-    impl NopProvider {
+    impl FallbackProvider {
         pub fn new() -> Self {
+            #[cfg(feature = "term")]
+            log::debug!(
+                "No native clipboard provider found. Yanking by OSC 52 and pasting will be internal to Helix"
+            );
+            #[cfg(not(feature = "term"))]
             log::warn!(
-                "No clipboard provider found! Yanking and pasting will be internal to Helix"
+                "No native clipboard provider found! Yanking and pasting will be internal to Helix"
             );
             Self {
                 buf: String::new(),
@@ -164,20 +203,27 @@ pub mod provider {
         }
     }
 
-    #[cfg(not(target_os = "windows"))]
-    impl Default for NopProvider {
+    impl Default for FallbackProvider {
         fn default() -> Self {
             Self::new()
         }
     }
 
-    #[cfg(not(target_os = "windows"))]
-    impl ClipboardProvider for NopProvider {
+    impl ClipboardProvider for FallbackProvider {
+        #[cfg(feature = "term")]
+        fn name(&self) -> Cow<str> {
+            Cow::Borrowed("termcode")
+        }
+
+        #[cfg(not(feature = "term"))]
         fn name(&self) -> Cow<str> {
             Cow::Borrowed("none")
         }
 
         fn get_contents(&self, clipboard_type: ClipboardType) -> Result<String> {
+            // This is the same noop if term is enabled or not.
+            // We don't use the get side of OSC 52 as it isn't often enabled, it's a security hole,
+            // and it would require this to be async to listen for the response
             let value = match clipboard_type {
                 ClipboardType::Clipboard => self.buf.clone(),
                 ClipboardType::Selection => self.primary_buf.clone(),
@@ -187,6 +233,12 @@ pub mod provider {
         }
 
         fn set_contents(&mut self, content: String, clipboard_type: ClipboardType) -> Result<()> {
+            #[cfg(feature = "term")]
+            crossterm::execute!(
+                std::io::stdout(),
+                osc52::SetClipboardCommand::new(&content, clipboard_type)
+            )?;
+            // Set our internal variables to use in get_content regardless of using OSC 52
             match clipboard_type {
                 ClipboardType::Clipboard => self.buf = content,
                 ClipboardType::Selection => self.primary_buf = content,
@@ -195,52 +247,11 @@ pub mod provider {
         }
     }
 
-    #[cfg(target_os = "windows")]
-    #[derive(Default, Debug)]
-    pub struct WindowsProvider;
-
-    #[cfg(target_os = "windows")]
-    impl ClipboardProvider for WindowsProvider {
-        fn name(&self) -> Cow<str> {
-            log::info!("Using clipboard-win to interact with the system clipboard");
-            Cow::Borrowed("clipboard-win")
-        }
-
-        fn get_contents(&self, clipboard_type: ClipboardType) -> Result<String> {
-            match clipboard_type {
-                ClipboardType::Clipboard => {
-                    let contents = clipboard_win::get_clipboard(clipboard_win::formats::Unicode)?;
-                    Ok(contents)
-                }
-                ClipboardType::Selection => Ok(String::new()),
-            }
-        }
-
-        fn set_contents(&mut self, contents: String, clipboard_type: ClipboardType) -> Result<()> {
-            match clipboard_type {
-                ClipboardType::Clipboard => {
-                    clipboard_win::set_clipboard(clipboard_win::formats::Unicode, contents)?;
-                }
-                ClipboardType::Selection => {}
-            };
-            Ok(())
-        }
-    }
-
     #[cfg(not(target_arch = "wasm32"))]
     pub mod command {
         use super::*;
         use anyhow::{bail, Context as _, Result};
 
-        pub fn exists(executable_name: &str) -> bool {
-            which::which(executable_name).is_ok()
-        }
-
-        #[cfg(not(windows))]
-        pub fn env_var_is_set(env_var_name: &str) -> bool {
-            std::env::var_os(env_var_name).is_some()
-        }
-
         #[cfg(not(any(windows, target_os = "macos")))]
         pub fn is_exit_success(program: &str, args: &[&str]) -> bool {
             std::process::Command::new(program)
@@ -343,3 +354,40 @@ pub mod provider {
         }
     }
 }
+
+#[cfg(target_os = "windows")]
+mod provider {
+    use super::{ClipboardProvider, ClipboardType};
+    use anyhow::Result;
+    use std::borrow::Cow;
+
+    #[derive(Default, Debug)]
+    pub struct WindowsProvider;
+
+    impl ClipboardProvider for WindowsProvider {
+        fn name(&self) -> Cow<str> {
+            log::info!("Using clipboard-win to interact with the system clipboard");
+            Cow::Borrowed("clipboard-win")
+        }
+
+        fn get_contents(&self, clipboard_type: ClipboardType) -> Result<String> {
+            match clipboard_type {
+                ClipboardType::Clipboard => {
+                    let contents = clipboard_win::get_clipboard(clipboard_win::formats::Unicode)?;
+                    Ok(contents)
+                }
+                ClipboardType::Selection => Ok(String::new()),
+            }
+        }
+
+        fn set_contents(&mut self, contents: String, clipboard_type: ClipboardType) -> Result<()> {
+            match clipboard_type {
+                ClipboardType::Clipboard => {
+                    clipboard_win::set_clipboard(clipboard_win::formats::Unicode, contents)?;
+                }
+                ClipboardType::Selection => {}
+            };
+            Ok(())
+        }
+    }
+}
diff --git a/helix-view/src/editor.rs b/helix-view/src/editor.rs
index af69ceea..47edf303 100644
--- a/helix-view/src/editor.rs
+++ b/helix-view/src/editor.rs
@@ -187,9 +187,9 @@ pub struct TerminalConfig {
 
 #[cfg(windows)]
 pub fn get_terminal_provider() -> Option<TerminalConfig> {
-    use crate::clipboard::provider::command::exists;
+    use crate::env::binary_exists;
 
-    if exists("wt") {
+    if binary_exists("wt") {
         return Some(TerminalConfig {
             command: "wt".to_string(),
             args: vec![
@@ -210,16 +210,16 @@ pub fn get_terminal_provider() -> Option<TerminalConfig> {
 
 #[cfg(not(any(windows, target_os = "wasm32")))]
 pub fn get_terminal_provider() -> Option<TerminalConfig> {
-    use crate::clipboard::provider::command::{env_var_is_set, exists};
+    use crate::env::{binary_exists, env_var_is_set};
 
-    if env_var_is_set("TMUX") && exists("tmux") {
+    if env_var_is_set("TMUX") && binary_exists("tmux") {
         return Some(TerminalConfig {
             command: "tmux".to_string(),
             args: vec!["split-window".to_string()],
         });
     }
 
-    if env_var_is_set("WEZTERM_UNIX_SOCKET") && exists("wezterm") {
+    if env_var_is_set("WEZTERM_UNIX_SOCKET") && binary_exists("wezterm") {
         return Some(TerminalConfig {
             command: "wezterm".to_string(),
             args: vec!["cli".to_string(), "split-pane".to_string()],
diff --git a/helix-view/src/env.rs b/helix-view/src/env.rs
new file mode 100644
index 00000000..c68cc609
--- /dev/null
+++ b/helix-view/src/env.rs
@@ -0,0 +1,8 @@
+pub fn binary_exists(binary_name: &str) -> bool {
+    which::which(binary_name).is_ok()
+}
+
+#[cfg(not(windows))]
+pub fn env_var_is_set(env_var_name: &str) -> bool {
+    std::env::var_os(env_var_name).is_some()
+}
diff --git a/helix-view/src/lib.rs b/helix-view/src/lib.rs
index 276be441..52044ac7 100644
--- a/helix-view/src/lib.rs
+++ b/helix-view/src/lib.rs
@@ -4,12 +4,14 @@ pub mod macros;
 pub mod clipboard;
 pub mod document;
 pub mod editor;
+pub mod env;
 pub mod graphics;
 pub mod gutter;
 pub mod handlers {
     pub mod dap;
     pub mod lsp;
 }
+pub mod base64;
 pub mod info;
 pub mod input;
 pub mod keyboard;