SwiftTerm icon indicating copy to clipboard operation
SwiftTerm copied to clipboard

Mouse selection offset when terminal is scrolled

Open blackmann opened this issue 3 weeks ago • 2 comments

Describe the bug When the terminal's content causes a scroll viewport, mouse selection doesn't work properly. I've spent two days going crazy over this and I'm not sure where to look anymore. See video

To Reproduce

  • Run a command (or some commands) that will cause the terminal to scroll (or show a scrollbar).
  • Attempt to select text at the bottom

Expected behavior The text at the bottom should be highlighted but it doesn't. However, when you scroll to the very top and make a selection, it works fine.

Screenshots

https://github.com/user-attachments/assets/632d2a7e-483c-456f-aee7-e4762b89fb62

Desktop (please complete the following information):

  • OS: MacOS 26.1

blackmann avatar Dec 06 '25 23:12 blackmann

In case it helps, here's a short Swift Playground reproduction:

import SwiftTerm
import Foundation
import SwiftUI
import PlaygroundSupport

struct ContentView: View {
  @State private var manager = TerminalManager()
  
  var body: some View {
    TerminalView()
      .frame(width: 300, height: 200)
      .environment(manager)
  }
}


struct TerminalView: View {
  @Environment(TerminalManager.self) private var manager
  
  var body: some View {
    GeometryReader { reader in
      VStack {
        if let first = manager.terminals.first {
          first
        }
      }
      .onAppear {
        manager.checkReady(frame: reader.frame(in: .local))
      }
    }
  }
}

struct TerminalInstance: NSViewRepresentable {
  let view: LocalProcessTerminalView
  
  init(frame: CGRect) {
    self.view = LocalProcessTerminalView(frame: frame)
    
    if let font = NSFont(name: "glass tty vt220", size: 13) {
      self.view.font = font
    }
  }
  
  func makeNSView(context: Context) -> some NSView {
    return view
  }
  
  func updateNSView(_ nsView: NSViewType, context: Context) {
    
  }
  
  func start() {
    view.startProcess(executable: "/bin/zsh", args: ["-l"])
  }
}

@Observable
class TerminalManager {
  var terminals: [TerminalInstance] = []
  
  func checkReady(frame: CGRect) {
    if terminals.isEmpty {
      addNewTerminal(frame: frame)
    }
  }
  
  func addNewTerminal(frame: CGRect) {
    let instance = TerminalInstance(frame: frame)
    terminals.append(instance)
    instance.start()
  }
}

PlaygroundPage.current.setLiveView(ContentView())

blackmann avatar Dec 07 '25 08:12 blackmann

What version are you using, I am not able to reproduce this when I run the MacTerminal example, and I can not get Swift Playgrounds to work for me.

Please upload a complete and self-contained sample.

migueldeicaza avatar Dec 09 '25 14:12 migueldeicaza

So the bug exists in 1.5.1.

I changed the dependency rule to "branch" and chose main. This issue is gone.

Closing!

blackmann avatar Dec 12 '25 12:12 blackmann