diff --git a/Cargo.lock b/Cargo.lock
index ba45884c..dc12edb2 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1511,6 +1511,7 @@ dependencies = [
  "konst",
  "proptest",
  "tek_tui",
+ "thiserror 2.0.11",
 ]
 
 [[package]]
@@ -1619,7 +1620,16 @@ version = "1.0.69"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52"
 dependencies = [
- "thiserror-impl",
+ "thiserror-impl 1.0.69",
+]
+
+[[package]]
+name = "thiserror"
+version = "2.0.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d452f284b73e6d76dd36758a0c8684b1d5be31f92b89d07fd5822175732206fc"
+dependencies = [
+ "thiserror-impl 2.0.11",
 ]
 
 [[package]]
@@ -1633,6 +1643,17 @@ dependencies = [
  "syn",
 ]
 
+[[package]]
+name = "thiserror-impl"
+version = "2.0.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "26afc1baea8a989337eeb52b6e72a039780ce45c3edfcc9c5b9d112feeb173c2"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
 [[package]]
 name = "toml"
 version = "0.8.19"
@@ -1820,7 +1841,7 @@ dependencies = [
  "i24",
  "num-traits",
  "paste",
- "thiserror",
+ "thiserror 1.0.69",
 ]
 
 [[package]]
diff --git a/edn/Cargo.toml b/edn/Cargo.toml
index a212ad6c..c064cfb1 100644
--- a/edn/Cargo.toml
+++ b/edn/Cargo.toml
@@ -7,6 +7,7 @@ version = "0.1.0"
 clojure-reader = "0.3.0"
 konst = { version = "0.3.16", features = [ "rust_1_83" ] }
 itertools = "0.14.0"
+thiserror = "2.0"
 
 [features]
 default = []
diff --git a/edn/src/context.rs b/edn/src/context.rs
index 2a8aa2ca..d7adc789 100644
--- a/edn/src/context.rs
+++ b/edn/src/context.rs
@@ -115,3 +115,16 @@ impl<T: Context<U>, U> Context<U> for Option<T> {
         }
     };
 }
+#[cfg(test)] #[test] fn test_edn_context () {
+    struct Test;
+    provide_bool!(bool: |self: Test|{
+        ":provide-bool" => true
+    });
+    let test = Test;
+    assert_eq!(test.get(&Value::Sym(":false")),        Some(false));
+    assert_eq!(test.get(&Value::Sym(":true")),         Some(true));
+    assert_eq!(test.get(&Value::Sym(":provide-bool")), Some(true));
+    assert_eq!(test.get(&Value::Sym(":missing-bool")), None);
+    assert_eq!(test.get(&Value::Num(0)), Some(false));
+    assert_eq!(test.get(&Value::Num(1)), Some(true));
+}
diff --git a/edn/src/error.rs b/edn/src/error.rs
index 24e40caf..40b687da 100644
--- a/edn/src/error.rs
+++ b/edn/src/error.rs
@@ -1,21 +1,15 @@
 use crate::*;
+use thiserror::Error;
 pub type ParseResult<T> = Result<T, ParseError>;
-#[derive(Debug, Copy, Clone, PartialEq)] pub enum ParseError {
+#[derive(Error, Debug, Copy, Clone, PartialEq)] pub enum ParseError {
+    #[error("parse failed: not implemented")]
     Unimplemented,
+    #[error("parse failed: empty")]
     Empty,
+    #[error("parse failed: incomplete")]
     Incomplete,
+    #[error("parse failed: unexpected character '{0}'")]
     Unexpected(char), 
+    #[error("parse failed: error #{0}")]
     Code(u8),
 }
-impl Error for ParseError {}
-impl Display for ParseError {
-    fn fmt (&self, f: &mut Formatter) -> FormatResult {
-        match self {
-            Unimplemented => write!(f, "unimplemented"),
-            Empty         => write!(f, "empty"),
-            Incomplete    => write!(f, "incomplete"),
-            Unexpected(c) => write!(f, "unexpected '{c}'"),
-            Code(i)       => write!(f, "error #{i}"),
-        }
-    }
-}
diff --git a/input/src/lib.rs b/input/src/lib.rs
index 3bd0fc5a..c6a0838a 100644
--- a/input/src/lib.rs
+++ b/input/src/lib.rs
@@ -25,5 +25,8 @@ pub(crate) type Perhaps<T> = Result<Option<T>, Box<dyn Error>>;
         }
         fn done (&self) {}
     }
+    let _ = TestInput(true).event();
+    assert!(TestInput(true).is_done());
+    assert!(!TestInput(false).is_done());
     Ok(())
 }
diff --git a/shell.nix b/shell.nix
index 78aa3b99..7f22e603 100755
--- a/shell.nix
+++ b/shell.nix
@@ -1,24 +1,13 @@
 #!/usr/bin/env nix-shell
 {pkgs?import<nixpkgs>{}}:let
-  #suil = pkgs.enableDebugging (pkgs.suil.overrideAttrs (a: b: {
-    #dontStrip = true; separateDebugInfo = true;
-  #}));
-in pkgs.mkShell {
-  nativeBuildInputs = with pkgs; [
-    pkg-config
-    freetype
-    libclang
-    #bear
-  ];
-  buildInputs = with pkgs; [
-    jack2
-    lilv
-    serd
-    libclang
-    #suil
-    glib
-    gtk3
-  ];
+  stdenv = pkgs.clang19Stdenv;
+  name = "tek";
+  nativeBuildInputs = with pkgs; [ pkg-config freetype libclang ];
+  buildInputs = with pkgs; let
+    #suil = pkgs.enableDebugging (pkgs.suil.overrideAttrs (a: b: {
+      #dontStrip = true; separateDebugInfo = true;
+    #}));
+  in [ jack2 lilv serd libclang /*suil*/ glib gtk3 ];
   VST3_SDK_DIR = "/home/user/Lab/Music/tek/vst3sdk/";
   LIBCLANG_PATH = "${pkgs.libclang.lib.outPath}/lib";
   LD_LIBRARY_PATH = pkgs.lib.makeLibraryPath (with pkgs; [
@@ -38,4 +27,8 @@ in pkgs.mkShell {
     libglvnd
     #xorg_sys_opengl
   ]);
+in pkgs.mkShell.override {
+  inherit stdenv;
+} {
+  inherit name nativeBuildInputs buildInputs VST3_SDK_DIR LIBCLANG_PATH LD_LIBRARY_PATH;
 }
diff --git a/tek/src/view_arranger.rs b/tek/src/view_arranger.rs
index 8bdcfab3..0fb33ce0 100644
--- a/tek/src/view_arranger.rs
+++ b/tek/src/view_arranger.rs
@@ -1,6 +1,11 @@
 use crate::*;
 impl Tek {
 
+    // FIXME: The memoized arranger is too complex.
+    // Just render a slice of the arranger for now,
+    // starting from tracks[scroll_offset] and ending
+    // at the last track that fits fully.
+
     /// Blit the currently visible section of the arranger view buffer to the output.
     ///
     /// If the arranger is larger than the available display area,
@@ -32,8 +37,8 @@ impl Tek {
     /// Draw the full arranger to the arranger view buffer.
     ///
     /// This should happen on changes to the arrangement contents,
-    /// i.e. not on scroll. Scrolling just determines which
-    /// part of the arranger buffer to blit in [view_arranger].
+    /// i.e. not on scroll. Scrolling just determines which part
+    /// of the arranger buffer to blit in [view_arranger].
     pub fn redraw_arranger (&self) {
         let width  = self.w_tracks();
         let height = self.h_scenes() + self.h_inputs() + self.h_outputs();