diff --git a/helix-core/src/state.rs b/helix-core/src/state.rs
index 0f94f696..75e5cd40 100644
--- a/helix-core/src/state.rs
+++ b/helix-core/src/state.rs
@@ -29,6 +29,7 @@ pub struct State {
     pub changes: ChangeSet,
     pub old_state: Option<(Rope, Selection)>,
 
+    pub version: i64,
     pub diagnostics: Vec<Diagnostic>,
 }
 
@@ -61,6 +62,7 @@ impl State {
             changes,
             old_state,
             diagnostics: Vec::new(),
+            version: 0,
         }
     }
 
diff --git a/helix-lsp/src/lib.rs b/helix-lsp/src/lib.rs
index 939f9927..f8c73902 100644
--- a/helix-lsp/src/lib.rs
+++ b/helix-lsp/src/lib.rs
@@ -2,6 +2,8 @@ mod transport;
 
 use transport::{Payload, Transport};
 
+use helix_core::{State, Transaction};
+
 // use std::collections::HashMap;
 
 use jsonrpc_core as jsonrpc;
@@ -13,14 +15,24 @@ use serde::{Deserialize, Serialize};
 pub use lsp::Position;
 pub use lsp::Url;
 
-use smol::prelude::*;
 use smol::{
     channel::{Receiver, Sender},
     io::{BufReader, BufWriter},
+    // prelude::*,
     process::{Child, ChildStderr, Command, Stdio},
     Executor,
 };
 
+pub mod util {
+    use super::*;
+
+    pub fn lsp_pos_to_pos(doc: &helix_core::RopeSlice, pos: lsp::Position) -> usize {
+        let line = doc.line_to_char(pos.line as usize);
+        let line_start = doc.char_to_utf16_cu(line);
+        doc.utf16_cu_to_char(pos.character as usize + line_start)
+    }
+}
+
 /// A type representing all possible values sent from the server to the client.
 #[derive(Debug, PartialEq, Clone, Deserialize, Serialize)]
 #[serde(deny_unknown_fields)]
@@ -58,7 +70,7 @@ impl Notification {
 }
 
 pub struct Client {
-    process: Child,
+    _process: Child,
     stderr: BufReader<ChildStderr>,
 
     outgoing: Sender<Payload>,
@@ -90,7 +102,7 @@ impl Client {
         let (incoming, outgoing) = Transport::start(ex, reader, writer);
 
         Client {
-            process,
+            _process: process,
             stderr,
 
             outgoing,
@@ -224,15 +236,12 @@ impl Client {
     // Text document
     // -------------------------------------------------------------------------------------------
 
-    pub async fn text_document_did_open(
-        &mut self,
-        state: &helix_core::State,
-    ) -> anyhow::Result<()> {
+    pub async fn text_document_did_open(&mut self, state: &State) -> anyhow::Result<()> {
         self.notify::<lsp::notification::DidOpenTextDocument>(lsp::DidOpenTextDocumentParams {
             text_document: lsp::TextDocumentItem {
                 uri: lsp::Url::from_file_path(state.path().unwrap()).unwrap(),
                 language_id: "rust".to_string(), // TODO: hardcoded for now
-                version: 0,
+                version: state.version,
                 text: String::from(&state.doc),
             },
         })
@@ -242,14 +251,15 @@ impl Client {
     // TODO: trigger any time history.commit_revision happens
     pub async fn text_document_did_change(
         &mut self,
-        state: &helix_core::State,
+        state: &State,
+        transaction: &Transaction,
     ) -> anyhow::Result<()> {
         self.notify::<lsp::notification::DidChangeTextDocument>(lsp::DidChangeTextDocumentParams {
             text_document: lsp::VersionedTextDocumentIdentifier::new(
                 lsp::Url::from_file_path(state.path().unwrap()).unwrap(),
-                0, // TODO: version
+                state.version,
             ),
-            content_changes: vec![], // TODO:
+            content_changes: vec![], // TODO: probably need old_state here too?
         })
         .await
     }
diff --git a/helix-term/src/application.rs b/helix-term/src/application.rs
index 5551e26f..a1a6b9ea 100644
--- a/helix-term/src/application.rs
+++ b/helix-term/src/application.rs
@@ -568,23 +568,12 @@ impl<'a> Application<'a> {
         use helix_lsp::Notification;
         match notification {
             Some(Notification::PublishDiagnostics(params)) => {
-                let view = self.editor.views.iter_mut().find(|view| {
-                    let path = view
-                        .state
-                        .path
-                        .as_ref()
-                        .map(|path| helix_lsp::Url::from_file_path(path).unwrap());
-
-                    eprintln!("{:?} {} {}", path, params.uri, params.diagnostics.len());
-                    // HAXX
-                    path == Some(params.uri.clone())
-                });
-
-                fn lsp_pos_to_pos(doc: &helix_core::RopeSlice, pos: helix_lsp::Position) -> usize {
-                    let line = doc.line_to_char(pos.line as usize);
-                    let line_start = doc.char_to_utf16_cu(line);
-                    doc.utf16_cu_to_char(pos.character as usize + line_start)
-                }
+                let path = Some(params.uri.to_file_path().unwrap());
+                let view = self
+                    .editor
+                    .views
+                    .iter_mut()
+                    .find(|view| view.state.path == path);
 
                 if let Some(view) = view {
                     let doc = view.state.doc().slice(..);
@@ -592,18 +581,10 @@ impl<'a> Application<'a> {
                         .diagnostics
                         .into_iter()
                         .map(|diagnostic| {
+                            use helix_lsp::util::lsp_pos_to_pos;
                             let start = lsp_pos_to_pos(&doc, diagnostic.range.start);
                             let end = lsp_pos_to_pos(&doc, diagnostic.range.end);
 
-                            // eprintln!(
-                            //     "{:?}-{:?} {}-{} {}",
-                            //     diagnostic.range.start,
-                            //     diagnostic.range.end,
-                            //     start,
-                            //     end,
-                            //     diagnostic.message
-                            // );
-
                             helix_core::Diagnostic {
                                 range: (start, end),
                                 line: diagnostic.range.start.line as usize,
diff --git a/helix-view/src/commands.rs b/helix-view/src/commands.rs
index 1d7737f0..e29d070e 100644
--- a/helix-view/src/commands.rs
+++ b/helix-view/src/commands.rs
@@ -391,6 +391,12 @@ fn append_changes_to_history(view: &mut View) {
     // annotations either add a new layer or compose into the previous one.
     let transaction = Transaction::from(changes).with_selection(view.state.selection().clone());
 
+    // increment document version
+    // TODO: needs to happen on undo/redo too
+    view.state.version += 1;
+
+    // TODO: trigger lsp/documentDidChange with changes
+
     // HAXX: we need to reconstruct the state as it was before the changes..
     let (doc, selection) = view.state.old_state.take().unwrap();
     let mut old_state = State::new(doc);
@@ -399,7 +405,6 @@ fn append_changes_to_history(view: &mut View) {
     // TODO: take transaction by value?
     view.history.commit_revision(&transaction, &old_state);
 
-    // TODO: need to start the state with these vals
     // HAXX
     view.state.old_state = Some((view.state.doc().clone(), view.state.selection.clone()));
 }