2

Context

I'm trying to write an interactive swift command line tool. A key part of this is having a "writeToScreen" function that takes as parameters a series of headers, footers, and then a body and formats them nicely to the current size of the terminal window, collapsing overflow into a "list" option. So the function would be something like:

func writeToScreen(_ headers: [String], _ footers: [String], _ body: String) {
    let (terminalWindowRows, terminalWindowCols) = getCurrentScreenSize()
    // perform formatting within this window size...
}

func getCurrentScreenSize() -> (Int, Int) {
    // perform some bash script like tput lines and tput cols and return result
}

And for example, an input like writeToScreen(["h1","h2"], ["longf1","longf2"], "body...") would produce the following for the respective screen sizes something like:

22x7
_ _ _ _ _ _ _ _ _ _ _ _
|(1) h1, (2) list...  |
|                     |
| body...             |
|                     |
|                     |
|                     |
|(3) list...          |
_ _ _ _ _ _ _ _ _ _ _ _

28x7
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _
|(1) h1, (2) h2, (3) list...|
|                           |
| body...                   |
|                           |
|                           |
|                           |
|(4) longf1, (5) list...    |
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _

Problem

The problem I'm having is that to get the terminal window size I need to run at least one bash script, say echo "$(tput cols)-$(tput lines)" which would output the screen size as <cols>-<rows>. However, running a bash script in swift involves using Process() or NSTask() which in every usage case I can find is always a separate process and therefore just returns the default terminal size irrespective of the current session window size.

I've tried using:

  1. https://github.com/kareman/SwiftShell run("tput", "cols") (always constant regardless of window size)
  2. How do I run an terminal command in a swift script? (e.g. xcodebuild) (same problem as above, just laid bare without an API)

Question

What do I need to do to get information about the current session or run my bash process in the context of the current window, specifically information about the window size?

I thought about trying something where I would list the current terminal sessions and run the bash script in one of those, but I couldn't figure out how to make that work (Something like bash who and then select the correct session and work from there. Not sure if that's a viable route.): https://askubuntu.com/questions/496914/write-command-in-one-terminal-see-result-on-other-one

Community
  • 1
  • 1
Ethan Kay
  • 657
  • 6
  • 24

1 Answers1

0

You can use this function to execute commands in bash:

func shell(_ command: String) -> String {
    let task = Process()
    task.launchPath = "/bin/bash"
    task.arguments = ["-c", command]

    let pipe = Pipe()
    task.standardOutput = pipe
    task.launch()

    let data = pipe.fileHandleForReading.readDataToEndOfFile()
    let output: String = NSString(data: data, encoding: String.Encoding.utf8.rawValue)! as String

    return output
}

And then simply use:

let cols = shell("tput cols")
let lines = shell("tput lines")

It will return as String so you may want to convert the output to Integer.

Hope that helped.