As promised, the refactored library allows for clean caching of decoration objects, so they are only re-computed when necessary.
OZ7NVILED6ZA6HUKY5IZHFU3Z7ASPLM62HFB2WZDQHWDKQHXQ6VAC RR6FDU64N3Y3B5L6YEWWORXMJRKFH6NRIMTLORNKBPWSKUZIFCNAC LQ3SUK3P3KXY5CQA552EJGFH2MESGNHKK4YZTIKOGFJAKVBMHHUQC BS2SCVKJS7HVJDGBLKPURU75NGJGH5YQ2KDAT6QNEYGUJBVS6FUQC 47DXBIWXK2U3VJZW5V4XZEARZBV4H3WG375BN4OWW5XY5DN42GEQC 37UOV7PCILKVEPDUBJHLHBZEOTQ5NX5FCV6MQWTRY5GM5KXZNDGAC 7X2GGEHDEWGZCDFD2IAGUGHIPNFWY76TTVNKOIV7YL3D5PMAXX4AC S34LGQX3XOVZUKWNE2YQNB3LJPXBBHP5GUYPYGTBFV63HYBLTQWAC fn change_at<'a>(&'a self, target_line: u32) -> Result<&'a Change, anyhow::Error> {let mut current_line: u64 = 0;for (hash, line_count) in &self.hashes {if (current_line..current_line + line_count).contains(&(target_line as u64)) {if hash == &self.current_state.hash()? {// Hash matches current statereturn Ok(&self.current_state);} else {for change in &self.recorded_changes {if &change.hash()? == hash {return Ok(&change);}}}}current_line += line_count;}bail!("Line outside of valid range");}
pub fn authors(&self) -> String {String::from("PLACEHOLDER AUTHOR")
pub fn authors_at(&self, target_line: u32) -> Result<String, anyhow::Error> {let change = self.change_at(target_line)?;if change == &self.current_state {Ok(String::from("You"))} else {Ok(String::from("You"))}
pub fn message(&self) -> String {String::from("PLACEHOLDER MESSAGE")
pub fn message_at(&self, target_line: u32) -> Result<String, anyhow::Error> {let change = self.change_at(target_line)?;if change == &self.current_state {Ok(String::from("Unrecorded changes"))} else {Ok(change.header.message.clone())}
const change_for_line = file_states.get(path);if (change_for_line === undefined) {console.error(`No cached state found for ${path}`);continue;}if (changes.length > 0) {if (changes[-1].hash() !== change_for_line.hash()) {changes.push(change_for_line);
const hash = file_state.hashAt(line);if (credits.length > 0) {if (credits[credits.length - 1].hash !== hash) {credits.push({hash,line,});
for (const change of changes) {const decoration_options: DecorationRenderOptions = {after: {// TODO: find a way to align this textcontentText: ` ${change.authors()} • ${change.message()}`,color: new ThemeColor("disabledForeground"),},isWholeLine: true,};const decoration_type =window.createTextEditorDecorationType(decoration_options);active_editor.setDecorations(decoration_type, active_editor.selections);decorations.push(decoration_type);
const new_decorations: Map<number, TextEditorDecorationType> = new Map();for (const change of credits) {const last_decoration = last_decorations.get(change.line);if (last_decoration !== undefined) {new_decorations.set(change.line, last_decoration);} else {const decoration_options: DecorationRenderOptions = {after: {// TODO: find a way to align this textcontentText: ` ${file_state.authorsAt(change.line,)} • ${file_state.messageAt(change.line)}`,color: new ThemeColor("disabledForeground"),},isWholeLine: true,};const decoration_type =window.createTextEditorDecorationType(decoration_options);const decoration_range: Range = new Range(change.line, 0, change.line, 0);active_editor.setDecorations(decoration_type, [decoration_range]);new_decorations.set(change.line, decoration_type);}}for (const [line, decoration] of last_decorations.entries()) {if (!new_decorations.has(line)) {console.log(`Dispose line ${line + 1}`);decoration.dispose();}