From 1cf9518e0f173641721b007ddc77e15f8cdeeb70 Mon Sep 17 00:00:00 2001 From: neon443 <69979447+neon443@users.noreply.github.com> Date: Sun, 22 Jun 2025 10:51:21 +0100 Subject: [PATCH] remove terminal string rewrote authWithPubkey() to not write files and take data direcytly remove read loop (comment adding it) readfromchannel returns string using swifterm to do terminal emulation --- ShhShell.xcodeproj/project.pbxproj | 93 ++++++------------- .../xcshareddata/swiftpm/Package.resolved | 28 +----- ShhShell/SSH/SSHHandler.swift | 47 ++++------ ShhShell/Views/ConnectionView.swift | 10 +- .../Views/Terminal/TerminalController.swift | 28 ++++++ .../Views/Terminal/TerminalDelegate.swift | 52 +++++++++++ ShhShell/Views/Terminal/TerminalView.swift | 43 --------- .../Views/Terminal/TextViewController.swift | 75 --------------- 8 files changed, 138 insertions(+), 238 deletions(-) create mode 100644 ShhShell/Views/Terminal/TerminalController.swift create mode 100644 ShhShell/Views/Terminal/TerminalDelegate.swift delete mode 100644 ShhShell/Views/Terminal/TerminalView.swift delete mode 100644 ShhShell/Views/Terminal/TextViewController.swift diff --git a/ShhShell.xcodeproj/project.pbxproj b/ShhShell.xcodeproj/project.pbxproj index e65559c..2d6a7cb 100644 --- a/ShhShell.xcodeproj/project.pbxproj +++ b/ShhShell.xcodeproj/project.pbxproj @@ -8,13 +8,9 @@ /* Begin PBXBuildFile section */ A9083E402DF2226F0042906E /* libz.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = A9083E3F2DF2225A0042906E /* libz.tbd */; }; - A91AE38A2DF722A700FF3537 /* Runestone in Frameworks */ = {isa = PBXBuildFile; productRef = A91AE3892DF722A600FF3537 /* Runestone */; }; - A91AE3B22DF73E0900FF3537 /* TerminalView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A91AE3B12DF73E0900FF3537 /* TerminalView.swift */; }; - A91AE3B52DF73F1D00FF3537 /* TreeSitterBash in Frameworks */ = {isa = PBXBuildFile; productRef = A91AE3B42DF73F1D00FF3537 /* TreeSitterBash */; }; - A91AE3B72DF73F1D00FF3537 /* TreeSitterBashQueries in Frameworks */ = {isa = PBXBuildFile; productRef = A91AE3B62DF73F1D00FF3537 /* TreeSitterBashQueries */; }; - A91AE3B92DF73F1D00FF3537 /* TreeSitterBashRunestone in Frameworks */ = {isa = PBXBuildFile; productRef = A91AE3B82DF73F1D00FF3537 /* TreeSitterBashRunestone */; }; - A91AE3BB2DF73F1D00FF3537 /* TreeSitterLanguagesCommon in Frameworks */ = {isa = PBXBuildFile; productRef = A91AE3BA2DF73F1D00FF3537 /* TreeSitterLanguagesCommon */; }; - A91AE3BD2DF7402100FF3537 /* TextViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A91AE3BC2DF7402100FF3537 /* TextViewController.swift */; }; + A92317282E07111E00ECE1E6 /* SwiftTerm in Frameworks */ = {isa = PBXBuildFile; productRef = A92317272E07111E00ECE1E6 /* SwiftTerm */; }; + A923172A2E07113100ECE1E6 /* TerminalController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A92317292E07113100ECE1E6 /* TerminalController.swift */; }; + A923172D2E07138000ECE1E6 /* TerminalDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = A923172C2E07138000ECE1E6 /* TerminalDelegate.swift */; }; A92538C82DEE0742007E0A18 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A92538C52DEE0742007E0A18 /* ContentView.swift */; }; A92538C92DEE0742007E0A18 /* ShhShellApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = A92538C62DEE0742007E0A18 /* ShhShellApp.swift */; }; A92538CA2DEE0742007E0A18 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = A92538C42DEE0742007E0A18 /* Assets.xcassets */; }; @@ -72,8 +68,8 @@ /* Begin PBXFileReference section */ A9083E3F2DF2225A0042906E /* libz.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libz.tbd; path = usr/lib/libz.tbd; sourceTree = SDKROOT; }; - A91AE3B12DF73E0900FF3537 /* TerminalView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TerminalView.swift; sourceTree = ""; }; - A91AE3BC2DF7402100FF3537 /* TextViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextViewController.swift; sourceTree = ""; }; + A92317292E07113100ECE1E6 /* TerminalController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TerminalController.swift; sourceTree = ""; }; + A923172C2E07138000ECE1E6 /* TerminalDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TerminalDelegate.swift; sourceTree = ""; }; A925389A2DEE06DC007E0A18 /* ShhShell.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = ShhShell.app; sourceTree = BUILT_PRODUCTS_DIR; }; A92538A72DEE06DE007E0A18 /* ShhShellTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = ShhShellTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; A92538B12DEE06DE007E0A18 /* ShhShellUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = ShhShellUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -107,13 +103,9 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - A91AE3B72DF73F1D00FF3537 /* TreeSitterBashQueries in Frameworks */, A95FAA542DF4B62900DE2F5A /* LibSSH.xcframework in Frameworks */, - A91AE3B52DF73F1D00FF3537 /* TreeSitterBash in Frameworks */, - A91AE3B92DF73F1D00FF3537 /* TreeSitterBashRunestone in Frameworks */, - A91AE38A2DF722A700FF3537 /* Runestone in Frameworks */, + A92317282E07111E00ECE1E6 /* SwiftTerm in Frameworks */, A93143BE2DF4D0B300FCD5DB /* libpthread.tbd in Frameworks */, - A91AE3BB2DF73F1D00FF3537 /* TreeSitterLanguagesCommon in Frameworks */, A9083E402DF2226F0042906E /* libz.tbd in Frameworks */, A95FAA562DF4B62A00DE2F5A /* openssl.xcframework in Frameworks */, ); @@ -136,6 +128,15 @@ /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + A923172B2E0712F200ECE1E6 /* Terminal */ = { + isa = PBXGroup; + children = ( + A92317292E07113100ECE1E6 /* TerminalController.swift */, + A923172C2E07138000ECE1E6 /* TerminalDelegate.swift */, + ); + path = Terminal; + sourceTree = ""; + }; A92538912DEE06DC007E0A18 = { isa = PBXGroup; children = ( @@ -197,8 +198,8 @@ A92538C52DEE0742007E0A18 /* ContentView.swift */, A98554622E0587DF009051BD /* HostsView.swift */, A985545C2E055D4D009051BD /* ConnectionView.swift */, - A98554522E055347009051BD /* Terminal */, A93143C52DF61FE300FCD5DB /* ViewModifiers.swift */, + A923172B2E0712F200ECE1E6 /* Terminal */, ); path = Views; sourceTree = ""; @@ -229,15 +230,6 @@ path = ci_scripts; sourceTree = ""; }; - A98554522E055347009051BD /* Terminal */ = { - isa = PBXGroup; - children = ( - A91AE3B12DF73E0900FF3537 /* TerminalView.swift */, - A91AE3BC2DF7402100FF3537 /* TextViewController.swift */, - ); - path = Terminal; - sourceTree = ""; - }; A98554532E05534F009051BD /* Keys */ = { isa = PBXGroup; children = ( @@ -293,11 +285,7 @@ ); name = ShhShell; packageProductDependencies = ( - A91AE3892DF722A600FF3537 /* Runestone */, - A91AE3B42DF73F1D00FF3537 /* TreeSitterBash */, - A91AE3B62DF73F1D00FF3537 /* TreeSitterBashQueries */, - A91AE3B82DF73F1D00FF3537 /* TreeSitterBashRunestone */, - A91AE3BA2DF73F1D00FF3537 /* TreeSitterLanguagesCommon */, + A92317272E07111E00ECE1E6 /* SwiftTerm */, ); productName = ShhShell; productReference = A925389A2DEE06DC007E0A18 /* ShhShell.app */; @@ -376,8 +364,7 @@ mainGroup = A92538912DEE06DC007E0A18; minimizedProjectReferenceProxies = 1; packageReferences = ( - A91AE3882DF722A600FF3537 /* XCRemoteSwiftPackageReference "runestone" */, - A91AE3B32DF73F1D00FF3537 /* XCRemoteSwiftPackageReference "treesitterlanguages" */, + A92317262E07111E00ECE1E6 /* XCRemoteSwiftPackageReference "SwiftTerm" */, ); preferredProjectObjectVersion = 77; productRefGroup = A925389B2DEE06DC007E0A18 /* Products */; @@ -430,11 +417,11 @@ A92538C92DEE0742007E0A18 /* ShhShellApp.swift in Sources */, A98554612E058433009051BD /* HostsManager.swift in Sources */, A985545D2E055D4D009051BD /* ConnectionView.swift in Sources */, - A91AE3B22DF73E0900FF3537 /* TerminalView.swift in Sources */, A98554592E0553AA009051BD /* KeyManager.swift in Sources */, - A91AE3BD2DF7402100FF3537 /* TextViewController.swift in Sources */, A9C897EF2DF1A9A400EF9A5F /* SSHHandler.swift in Sources */, A98554552E05535F009051BD /* KeyManagerView.swift in Sources */, + A923172D2E07138000ECE1E6 /* TerminalDelegate.swift in Sources */, + A923172A2E07113100ECE1E6 /* TerminalController.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -770,49 +757,21 @@ /* End XCConfigurationList section */ /* Begin XCRemoteSwiftPackageReference section */ - A91AE3882DF722A600FF3537 /* XCRemoteSwiftPackageReference "runestone" */ = { + A92317262E07111E00ECE1E6 /* XCRemoteSwiftPackageReference "SwiftTerm" */ = { isa = XCRemoteSwiftPackageReference; - repositoryURL = "https://github.com/simonbs/runestone"; + repositoryURL = "https://github.com/migueldeicaza/SwiftTerm"; requirement = { kind = upToNextMajorVersion; - minimumVersion = 0.5.1; - }; - }; - A91AE3B32DF73F1D00FF3537 /* XCRemoteSwiftPackageReference "treesitterlanguages" */ = { - isa = XCRemoteSwiftPackageReference; - repositoryURL = "https://github.com/simonbs/treesitterlanguages"; - requirement = { - kind = upToNextMajorVersion; - minimumVersion = 0.1.10; + minimumVersion = 1.2.5; }; }; /* End XCRemoteSwiftPackageReference section */ /* Begin XCSwiftPackageProductDependency section */ - A91AE3892DF722A600FF3537 /* Runestone */ = { + A92317272E07111E00ECE1E6 /* SwiftTerm */ = { isa = XCSwiftPackageProductDependency; - package = A91AE3882DF722A600FF3537 /* XCRemoteSwiftPackageReference "runestone" */; - productName = Runestone; - }; - A91AE3B42DF73F1D00FF3537 /* TreeSitterBash */ = { - isa = XCSwiftPackageProductDependency; - package = A91AE3B32DF73F1D00FF3537 /* XCRemoteSwiftPackageReference "treesitterlanguages" */; - productName = TreeSitterBash; - }; - A91AE3B62DF73F1D00FF3537 /* TreeSitterBashQueries */ = { - isa = XCSwiftPackageProductDependency; - package = A91AE3B32DF73F1D00FF3537 /* XCRemoteSwiftPackageReference "treesitterlanguages" */; - productName = TreeSitterBashQueries; - }; - A91AE3B82DF73F1D00FF3537 /* TreeSitterBashRunestone */ = { - isa = XCSwiftPackageProductDependency; - package = A91AE3B32DF73F1D00FF3537 /* XCRemoteSwiftPackageReference "treesitterlanguages" */; - productName = TreeSitterBashRunestone; - }; - A91AE3BA2DF73F1D00FF3537 /* TreeSitterLanguagesCommon */ = { - isa = XCSwiftPackageProductDependency; - package = A91AE3B32DF73F1D00FF3537 /* XCRemoteSwiftPackageReference "treesitterlanguages" */; - productName = TreeSitterLanguagesCommon; + package = A92317262E07111E00ECE1E6 /* XCRemoteSwiftPackageReference "SwiftTerm" */; + productName = SwiftTerm; }; /* End XCSwiftPackageProductDependency section */ }; diff --git a/ShhShell.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/ShhShell.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index 84bf99c..19775ed 100644 --- a/ShhShell.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/ShhShell.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -1,31 +1,13 @@ { - "originHash" : "7b91b8af81dcd3e1958c781705a4b5920fdcdef24313a6e025be307b7bc092d5", + "originHash" : "4d9d9af82f23f3c708bdd502fed3939413b4f2a95a79ae568364cc92bca1527e", "pins" : [ { - "identity" : "runestone", + "identity" : "swiftterm", "kind" : "remoteSourceControl", - "location" : "https://github.com/simonbs/Runestone", + "location" : "https://github.com/migueldeicaza/SwiftTerm", "state" : { - "revision" : "1fad339aab99cf2136ce6bf8c32da3265b2e85e5", - "version" : "0.5.1" - } - }, - { - "identity" : "tree-sitter", - "kind" : "remoteSourceControl", - "location" : "https://github.com/tree-sitter/tree-sitter", - "state" : { - "revision" : "98be227227af10cc7a269cb3ffb23686c0610b17", - "version" : "0.20.9" - } - }, - { - "identity" : "treesitterlanguages", - "kind" : "remoteSourceControl", - "location" : "https://github.com/simonbs/treesitterlanguages", - "state" : { - "revision" : "15cf3a9ec3ab95e0d058b7df9f35619123c9e02d", - "version" : "0.1.10" + "revision" : "e2b431dbf73f775fb4807a33e4572ffd3dc6933a", + "version" : "1.2.5" } } ], diff --git a/ShhShell/SSH/SSHHandler.swift b/ShhShell/SSH/SSHHandler.swift index fe45992..40d23ad 100644 --- a/ShhShell/SSH/SSHHandler.swift +++ b/ShhShell/SSH/SSHHandler.swift @@ -20,7 +20,6 @@ class SSHHandler: ObservableObject { @Published var testSuceeded: Bool? = nil @Published var host: Host - @Published var terminal: String = "" private let userDefaults = NSUbiquitousKeyValueStore.default private let logger = Logger(subsystem: "xy", category: "sshHandler") @@ -88,7 +87,6 @@ class SSHHandler: ObservableObject { withAnimation { connected = false } withAnimation { testSuceeded = nil } session = nil - terminal = "" // host.key = nil } @@ -173,28 +171,29 @@ class SSHHandler: ObservableObject { withAnimation { authorized = false } return } - var status: Int32 - let fileManager = FileManager.default - let tempDir = fileManager.temporaryDirectory - let tempPubkey = tempDir.appendingPathComponent("key.pub") - let tempKey = tempDir.appendingPathComponent("key") - fileManager.createFile(atPath: tempPubkey.path(), contents: nil) - fileManager.createFile(atPath: tempKey.path(), contents: nil) + print(pubInp) + var pubInpCChar: [Int8] = [] + for byte in pubInp { + pubInpCChar.append(Int8(byte)) + } - try? pubInp.write(to: tempPubkey) - try? privInp.write(to: tempKey) + var privInpCChar: [Int8] = [] + for byte in privInp { + privInpCChar.append(Int8(byte)) + } var pubkey: ssh_key? - ssh_pki_import_pubkey_file(tempPubkey.path(), &pubkey) + + ssh_pki_import_pubkey_base64(&pubInpCChar, SSH_KEYTYPE_SK_ED25519, &pubkey) status = ssh_userauth_try_publickey(session, nil, pubkey) print(status) var privkey: ssh_key? - if ssh_pki_import_privkey_file(tempKey.path(), pass, nil, nil, &privkey) != 0 { + if ssh_pki_import_privkey_base64(&privInpCChar, pass, nil, nil, &privkey) != 0 { print("help?!?") - print("likeley password is incorrect") + print("likeley passphrase is incorrect") } status = ssh_userauth_publickey(session, nil, privkey) @@ -207,11 +206,6 @@ class SSHHandler: ObservableObject { withAnimation { authorized = true } return //if u got this far, youre authed! - //cleanpu here: -// ssh_key_free(pubkey) -// ssh_key_free(privkey) -// try? fileManager.removeItem(at: tempPubkey) -// try? fileManager.removeItem(at: tempKey) } func authWithPw() -> Bool { @@ -305,26 +299,25 @@ class SSHHandler: ObservableObject { self.readTimer = nil return } - self.readFromChannel() } - RunLoop.main.add(self.readTimer!, forMode: .common) +// RunLoop.main.add(self.readTimer!, forMode: .common) } - func readFromChannel() { - guard ssh_channel_is_open(channel) != 0 else { return } - guard ssh_channel_is_eof(channel) == 0 else { return } + func readFromChannel() -> String { + guard ssh_channel_is_open(channel) != 0 else { return "" } + guard ssh_channel_is_eof(channel) == 0 else { return "" } var buffer: [CChar] = Array(repeating: 0, count: 256) let nbytes = ssh_channel_read_nonblocking(channel, &buffer, UInt32(buffer.count), 0) - guard nbytes > 0 else { return } + guard nbytes > 0 else { return "" } write(1, buffer, Int(nbytes)) let data = Data(bytes: buffer, count: buffer.count) if let string = String(data: data, encoding: .utf8) { - self.terminal.append(string) - terminal = self.terminal.replacingOccurrences(of: "[K", with: "\n") + return string } + return "" } private func logSshGetError() { diff --git a/ShhShell/Views/ConnectionView.swift b/ShhShell/Views/ConnectionView.swift index c9504d6..6ad0e71 100644 --- a/ShhShell/Views/ConnectionView.swift +++ b/ShhShell/Views/ConnectionView.swift @@ -75,7 +75,7 @@ struct ConnectionView: View { .fileImporter(isPresented: $pubPickerPresented, allowedContentTypes: [.item, .content, .data]) { (Result) in do { let fileURL = try Result.get() - pubkey = try! Data(contentsOf: fileURL) + pubkey = try? Data(contentsOf: fileURL) print(fileURL) } catch { print(error.localizedDescription) @@ -97,7 +97,8 @@ struct ConnectionView: View { .fileImporter(isPresented: $privPickerPresented, allowedContentTypes: [.item, .content, .data]) { (Result) in do { let fileURL = try Result.get() - privkey = try! Data(contentsOf: fileURL) + privkey = try? Data(contentsOf: fileURL) + print(privkey) print(fileURL) } catch { print(error.localizedDescription) @@ -119,7 +120,10 @@ struct ConnectionView: View { } NavigationLink() { - TerminalView(handler: handler) + Button("Reload") { + handler.readFromChannel() + } + TerminalController(handler: handler) } label: { Label("Open Terminal", systemImage: "apple.terminal") } diff --git a/ShhShell/Views/Terminal/TerminalController.swift b/ShhShell/Views/Terminal/TerminalController.swift new file mode 100644 index 0000000..42631a7 --- /dev/null +++ b/ShhShell/Views/Terminal/TerminalController.swift @@ -0,0 +1,28 @@ +// +// TerminalController.swift +// ShhShell +// +// Created by neon443 on 21/06/2025. +// + +import Foundation +import UIKit +import SwiftUI +import SwiftTerm + +struct TerminalController: UIViewRepresentable { + @ObservedObject var handler: SSHHandler + + func makeUIView(context: Context) -> TerminalView { + let tv = TerminalView() + let terminalDelegate = ShhTerminalViewDelegate() + tv.terminalDelegate = terminalDelegate + + tv.getTerminal().feed(text: handler.readFromChannel()) + return tv + } + + func updateUIView(_ tv: TerminalView, context: Context) { + tv.getTerminal().feed(text: handler.readFromChannel()) + } +} diff --git a/ShhShell/Views/Terminal/TerminalDelegate.swift b/ShhShell/Views/Terminal/TerminalDelegate.swift new file mode 100644 index 0000000..3f377fd --- /dev/null +++ b/ShhShell/Views/Terminal/TerminalDelegate.swift @@ -0,0 +1,52 @@ +// +// TerminalDelegate.swift +// ShhShell +// +// Created by neon443 on 21/06/2025. +// + +import Foundation +import SwiftTerm + +class ShhTerminalViewDelegate: TerminalViewDelegate { + func sizeChanged(source: TerminalView, newCols: Int, newRows: Int) { + print(newRows, newCols) + } + + func setTerminalTitle(source: TerminalView, title: String) { + print(title) + } + + func hostCurrentDirectoryUpdate(source: TerminalView, directory: String?) { + print(directory) + } + + func send(source: TerminalView, data: ArraySlice) { + print(data) + } + + func scrolled(source: TerminalView, position: Double) { + print(position) + } + + func requestOpenLink(source: TerminalView, link: String, params: [String : String]) { + print(link) + print(params) + } + + func bell(source: TerminalView) { + print("ding") + } + + func clipboardCopy(source: TerminalView, content: Data) { + print(content) + } + + func iTermContent(source: TerminalView, content: ArraySlice) { + print("idk what this does") + } + + func rangeChanged(source: TerminalView, startY: Int, endY: Int) { + print(startY, endY) + } +} diff --git a/ShhShell/Views/Terminal/TerminalView.swift b/ShhShell/Views/Terminal/TerminalView.swift deleted file mode 100644 index db75fb3..0000000 --- a/ShhShell/Views/Terminal/TerminalView.swift +++ /dev/null @@ -1,43 +0,0 @@ -// -// TerminalView.swift -// ShhShell -// -// Created by neon443 on 09/06/2025. -// - -import SwiftUI -import Runestone - -struct TerminalView: View { - @ObservedObject var handler: SSHHandler - @Environment(\.dismiss) var dismiss - - var body: some View { - Button("write") { - handler.writeToChannel("top\n") - } - TextViewController(handler: handler) - .toolbar { - ToolbarItem(placement: .cancellationAction) { - Button("reload") { - handler.readFromChannel() - } - } - ToolbarItem(placement: .confirmationAction) { - Button() { - handler.disconnect() - withAnimation { handler.testSuceeded = false } - withAnimation { handler.connected = false } - dismiss() - } label: { - Label("Exit", systemImage: "xmark.square.fill") - } - .disabled(!handler.connected) - } - } - } -} - -#Preview { - TerminalView(handler: SSHHandler(host: Host.debug)) -} diff --git a/ShhShell/Views/Terminal/TextViewController.swift b/ShhShell/Views/Terminal/TextViewController.swift deleted file mode 100644 index 65cdf39..0000000 --- a/ShhShell/Views/Terminal/TextViewController.swift +++ /dev/null @@ -1,75 +0,0 @@ -// -// TextViewController.swift -// ShhShell -// -// Created by neon443 on 09/06/2025. -// - -import Foundation -import UIKit -import SwiftUI -import Runestone -import TreeSitterBashRunestone - -struct TextViewController: UIViewRepresentable { - @ObservedObject var handler: SSHHandler - - func makeUIView(context: Context) -> TextView { - let languageMode = TreeSitterLanguageMode(language: .bash) - let textView = TextView() - setTextViewState(on: textView) - - var editorDelegate = textView.editorDelegate - editorDelegate = TerminalViewDelegate(handler: handler) - textView.editorDelegate = editorDelegate - - textView.translatesAutoresizingMaskIntoConstraints = false - textView.backgroundColor = .systemBackground - return textView - } - - func updateUIView(_ textView: TextView, context: Context) { - textView.text = handler.terminal - } - - private func setTextViewState(on textView: TextView) { - let text = handler.terminal - DispatchQueue.global(qos: .userInitiated).async { - let state = TextViewState(text: text, language: .bash) - DispatchQueue.main.async { - textView.setState(state) - } - } - } -} - -class TerminalViewDelegate: TextViewDelegate { - @ObservedObject var handler: SSHHandler - - init(handler: SSHHandler) { - self.handler = handler - } - - func textViewDidChangeGutterWidth(_ textView: TextView) { - print(textView.gutterWidth) - } - - func textViewDidChange(_ textView: TextView) { - handler.writeToChannel(textView.text) - } - - func textView(_ textView: TextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool { - print(range) - print(text) - return true - } - - func textViewShouldBeginEditing(_ textView: TextView) -> Bool { - print("can edit") - return true - } - - func textView(_ textView: TextView, shouldInsert characterPair: any CharacterPair, in range: NSRange) -> Bool { - return false - } -}