                 }
                 self?.needsDisplay = true
             }
-        
-        self.selectionObserver?.cancel()
-        self.selectionObserver = NotificationCenter.default.publisher(for: EditorTextView.didLiveChangeSelectionNotification, object: textView)
+            .store(in: &self.textViewSubscriptions)
+        
+        NotificationCenter.default.publisher(for: EditorTextView.didLiveChangeSelectionNotification, object: textView)
             .sink { [weak self] _ in
                 self?.needsDisplay = true
             }
-        
-        self.frameObserver?.cancel()
-        self.frameObserver = NotificationCenter.default.publisher(for: NSView.frameDidChangeNotification, object: textView)
+            .store(in: &self.textViewSubscriptions)
+        
+        NotificationCenter.default.publisher(for: NSView.frameDidChangeNotification, object: textView)
             .sink { [weak self] _ in
                 self?.needsDisplay = true
             }
-        
-        self.scrollObserver?.cancel()
-        self.scrollObserver = NotificationCenter.default.publisher(for: NSView.boundsDidChangeNotification, object: textView.enclosingScrollView?.contentView)
+            .store(in: &self.textViewSubscriptions)
+        
+        NotificationCenter.default.publisher(for: NSView.boundsDidChangeNotification, object: textView.enclosingScrollView?.contentView)
             .sink { [weak self] _ in
                 self?.needsDisplay = true
             }
-        
-        self.colorObserver?.cancel()
-        self.colorObserver = textView.publisher(for: \.backgroundColor)
-            .sink { [weak self] _  in
+            .store(in: &self.textViewSubscriptions)
+        
+        textView.publisher(for: \.backgroundColor)
+            .sink { [weak self] _ in
                 self?.needsDisplay = true
             }
-        
-        self.fontObserver?.cancel()
-        self.fontObserver = textView.publisher(for: \.font)
-            .sink { [weak self] _  in
+            .store(in: &self.textViewSubscriptions)
+        
+        textView.publisher(for: \.font)
+            .sink { [weak self] _ in
                 self?.invalidateDrawingInfo()
             }
-        
-        self.scaleObserver?.cancel()
-        self.scaleObserver = textView.publisher(for: \.scale)
-            .sink { [weak self] _  in
+            .store(in: &self.textViewSubscriptions)
+        
+        textView.publisher(for: \.scale)
+            .sink { [weak self] _ in
                 self?.invalidateDrawingInfo()
             }
-    }
-    
-    
-    /// remove observers observing textView
-    private func removeTextViewObservers() {
-        
-        assert(self.textView != nil)
-        assert(self.textView?.enclosingScrollView?.contentView != nil || self.scrollObserver == nil)
-        
-        self.textObserver?.cancel()
-        self.textObserver = nil
-        
-        self.selectionObserver?.cancel()
-        self.selectionObserver = nil
-        
-        self.frameObserver?.cancel()
-        self.frameObserver = nil
-        
-        self.scrollObserver?.cancel()
-        self.scrollObserver = nil
-        
-        self.colorObserver?.cancel()
-        self.colorObserver = nil
-        
-        self.fontObserver?.cancel()
-        self.fontObserver = nil
-        
-        self.scaleObserver?.cancel()
-        self.scaleObserver = nil
+            .store(in: &self.textViewSubscriptions)
     }
     
 }

        
        // remove observations before all observed objects are deallocated
        if newWindow == nil {
            self.removeTextViewObservers()
        }
        
        // perform redraw on window opacity change

    private var thickness: CGFloat = 32
    
    private var opacityObserver: AnyCancellable?
    private var textViewSubscriptions: Set<AnyCancellable> = []
    
    private weak var draggingTimer: Timer?
    
