diff --git a/Config.xcconfig b/Config.xcconfig index e46d6ae..cfdae9f 100644 --- a/Config.xcconfig +++ b/Config.xcconfig @@ -6,7 +6,7 @@ // VERSION = 0.1 -BUILD = 1 +BUILD = 3 // Configuration settings file format documentation can be found at: // https://developer.apple.com/documentation/xcode/adding-a-build-configuration-file-to-your-project diff --git a/ShhShell.xcodeproj/project.pbxproj b/ShhShell.xcodeproj/project.pbxproj index 79634ad..d2b4cd1 100644 --- a/ShhShell.xcodeproj/project.pbxproj +++ b/ShhShell.xcodeproj/project.pbxproj @@ -8,6 +8,13 @@ /* 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 */; }; 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 */; }; @@ -59,6 +66,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 = ""; }; 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; }; @@ -86,8 +95,13 @@ 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 */, A93143BE2DF4D0B300FCD5DB /* libpthread.tbd in Frameworks */, + A91AE3BB2DF73F1D00FF3537 /* TreeSitterLanguagesCommon in Frameworks */, A9083E402DF2226F0042906E /* libz.tbd in Frameworks */, A95FAA562DF4B62A00DE2F5A /* openssl.xcframework in Frameworks */, ); @@ -166,6 +180,8 @@ isa = PBXGroup; children = ( A92538C52DEE0742007E0A18 /* ContentView.swift */, + A91AE3B12DF73E0900FF3537 /* TerminalView.swift */, + A91AE3BC2DF7402100FF3537 /* TextViewController.swift */, A93143C52DF61FE300FCD5DB /* ViewModifiers.swift */, ); path = Views; @@ -227,6 +243,11 @@ ); name = ShhShell; packageProductDependencies = ( + A91AE3892DF722A600FF3537 /* Runestone */, + A91AE3B42DF73F1D00FF3537 /* TreeSitterBash */, + A91AE3B62DF73F1D00FF3537 /* TreeSitterBashQueries */, + A91AE3B82DF73F1D00FF3537 /* TreeSitterBashRunestone */, + A91AE3BA2DF73F1D00FF3537 /* TreeSitterLanguagesCommon */, ); productName = ShhShell; productReference = A925389A2DEE06DC007E0A18 /* ShhShell.app */; @@ -305,6 +326,8 @@ mainGroup = A92538912DEE06DC007E0A18; minimizedProjectReferenceProxies = 1; packageReferences = ( + A91AE3882DF722A600FF3537 /* XCRemoteSwiftPackageReference "runestone" */, + A91AE3B32DF73F1D00FF3537 /* XCRemoteSwiftPackageReference "treesitterlanguages" */, ); preferredProjectObjectVersion = 77; productRefGroup = A925389B2DEE06DC007E0A18 /* Products */; @@ -353,6 +376,8 @@ A92538C82DEE0742007E0A18 /* ContentView.swift in Sources */, A93143C02DF61B3200FCD5DB /* Host.swift in Sources */, A92538C92DEE0742007E0A18 /* ShhShellApp.swift in Sources */, + A91AE3B22DF73E0900FF3537 /* TerminalView.swift in Sources */, + A91AE3BD2DF7402100FF3537 /* TextViewController.swift in Sources */, A9C897EF2DF1A9A400EF9A5F /* SSHHandler.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -687,6 +712,53 @@ defaultConfigurationName = Release; }; /* End XCConfigurationList section */ + +/* Begin XCRemoteSwiftPackageReference section */ + A91AE3882DF722A600FF3537 /* XCRemoteSwiftPackageReference "runestone" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/simonbs/runestone"; + 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; + }; + }; +/* End XCRemoteSwiftPackageReference section */ + +/* Begin XCSwiftPackageProductDependency section */ + A91AE3892DF722A600FF3537 /* Runestone */ = { + 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; + }; +/* End XCSwiftPackageProductDependency section */ }; rootObject = A92538922DEE06DC007E0A18 /* Project object */; } diff --git a/ShhShell.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/ShhShell.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved new file mode 100644 index 0000000..84bf99c --- /dev/null +++ b/ShhShell.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -0,0 +1,33 @@ +{ + "originHash" : "7b91b8af81dcd3e1958c781705a4b5920fdcdef24313a6e025be307b7bc092d5", + "pins" : [ + { + "identity" : "runestone", + "kind" : "remoteSourceControl", + "location" : "https://github.com/simonbs/Runestone", + "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" + } + } + ], + "version" : 3 +} diff --git a/ShhShell/SSH/SSHHandler.swift b/ShhShell/SSH/SSHHandler.swift index 6edd891..8886a3c 100644 --- a/ShhShell/SSH/SSHHandler.swift +++ b/ShhShell/SSH/SSHHandler.swift @@ -16,6 +16,7 @@ class SSHHandler: ObservableObject { @Published var authorized: Bool = false @Published var host: HostPr + @Published var terminal: String = "" private let userDefaults = NSUbiquitousKeyValueStore.default private let logger = Logger(subsystem: "xy", category: "sshHandler") @@ -301,18 +302,18 @@ class SSHHandler: ObservableObject { } } - func readFromChannel() -> String? { - guard ssh_channel_is_open(channel) != 0 else { return nil } - guard ssh_channel_is_eof(channel) == 0 else { return nil } + func readFromChannel() { + 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 nil } + guard nbytes > 0 else { return } write(1, buffer, Int(nbytes)) let data = Data(bytes: buffer, count: buffer.count) - return String(data: data, encoding: .utf8)! + self.terminal.append(String(data: data, encoding: .utf8)!) } private func logSshGetError() { diff --git a/ShhShell/Views/ContentView.swift b/ShhShell/Views/ContentView.swift index 6889008..b62038f 100644 --- a/ShhShell/Views/ContentView.swift +++ b/ShhShell/Views/ContentView.swift @@ -12,8 +12,6 @@ struct ContentView: View { @State var connected: Bool = false @State var testSucceded: Bool? - @State var terminal: String = "" - var body: some View { VStack { Text(connected ? "connected" : "not connected") @@ -76,14 +74,13 @@ struct ContentView: View { Button("request a shell") { handler.openShell() - terminal.append(handler.readFromChannel() ?? "") } Button("read from server") { - terminal.append(handler.readFromChannel() ?? "") + handler.readFromChannel() } - Text(terminal) + TerminalView(handler: handler) } } } diff --git a/ShhShell/Views/TerminalView.swift b/ShhShell/Views/TerminalView.swift new file mode 100644 index 0000000..d8d1d77 --- /dev/null +++ b/ShhShell/Views/TerminalView.swift @@ -0,0 +1,21 @@ +// +// TerminalView.swift +// ShhShell +// +// Created by neon443 on 09/06/2025. +// + +import SwiftUI +import Runestone + +struct TerminalView: View { + @ObservedObject var handler: SSHHandler + + var body: some View { + TextViewController(text: $handler.host.address) + } +} + +#Preview { + TerminalView(handler: SSHHandler(host: debugHost())) +} diff --git a/ShhShell/Views/TextViewController.swift b/ShhShell/Views/TextViewController.swift new file mode 100644 index 0000000..dacd14b --- /dev/null +++ b/ShhShell/Views/TextViewController.swift @@ -0,0 +1,24 @@ +// +// TextViewController.swift +// ShhShell +// +// Created by neon443 on 09/06/2025. +// + +import Foundation +import UIKit +import SwiftUI +import Runestone + +struct TextViewController: UIViewRepresentable { + @Binding var text: String + + func makeUIView(context: Context) -> TextView { + var textView = TextView() + return textView + } + + func updateUIView(_ textView: TextView, context: Context) { + textView.text = text + } +}