Determine viewport size (in characters) from command line app in Swift? - swift

I am building a command line tool in Swift and am wondering if there is any way to determine the current width of the viewport while running the app, in order to limit the text on screen to what will fit without wrapping.
I know this is possible in a "real" command line app, since things like pico, man, pine, etc. all render their textual interfaces based on the window size, but I can't seem to find any info on how they do it.
In fact you can even resize the window while they are running and they will refresh. Does anyone know how this works and if it's possible to add support to a command line tool written in Swift?

The C code from Getting terminal width in C? is easily translated to Swift:
import Darwin
var w = winsize()
if ioctl(STDOUT_FILENO, TIOCGWINSZ, &w) == 0 {
print("rows:", w.ws_row, "cols", w.ws_col)
}
(For some reason, this does not work in the Xcode debugger console,
you have to call the executable in the Terminal window.)
Alternatively, using the ncurses library (from Getting terminal width in C?):
import Darwin.ncurses
initscr()
let s = "rows: \(LINES), cols: \(COLS)"
mvaddstr(1, 1, s);
refresh();
getch()
endwin()
To keep track of window resize events you have to handle the
SIGWINCH signal, compare Trapping signals in a Swift command line application:
import Darwin
import Dispatch
var w = winsize()
if ioctl(STDOUT_FILENO, TIOCGWINSZ, &w) == 0 {
print("rows:", w.ws_row, "cols", w.ws_col)
}
let sigwinchSrc = DispatchSource.makeSignalSource(signal: SIGWINCH, queue: .main)
sigwinchSrc.setEventHandler {
if ioctl(STDOUT_FILENO, TIOCGWINSZ, &w) == 0 {
print("rows:", w.ws_row, "cols", w.ws_col)
}
}
sigwinchSrc.resume()
dispatchMain()

Related

Creating Variable Number of Windows in SwiftUI

I am trying to plot multiple arrays during each execution, and each plot is presented in a different window in a macOS app. But each execution may have a different number of plots, therefore a different number of windows is needed. This is similar to using matplotlib library in Python. How can I do this in SwiftUI? If there was a scene container and ForEachScene construct, similar to view containers and ForEach, then this would have been easy I believe.
I was able to create a fixed number of plots (2 plots) in the following code. Here MyPlot is a view that produces the chart graph of an array; feel free to replace it with any view such as Text view in your answer. I also would like to see all the windows already opened. To achieve this I used the first window titled "xyz" to open the other two windows programmatically. Is there a way to do this without using an additional window such as the "xyz" window, which opens them but goes in front of them and hides them?
#main
struct MultipleWIndowsTrialsApp: App {
#Environment(\.openWindow) var openWindow
var body: some Scene {
Window("xyz", id: "xyz") {
EmptyView().onAppear() {
openWindow(id: "plot1")
openWindow(id: "plot2")
}
}
Window("Variation1", id: "plot1") {
MyPlot(y: [8.0, 5.0, -2.0, -2.0, 3.0, 1.0])
}
Window("Variations2", id: "plot2") {
MyPlot(y: [1.0, 2, 3, -2, -1, 0])
}
}
}

Xcode 8.3.2 Playground Console not Showing Anything

I am a beginning Swift programmer and I am making an area calculator in Xcode to practice my use of functions. However, when I finished writing my code I noticed that the console in Xcode would not print out anything. Is there anything wrong with my code or is it just that the Xcode console is kind of not working and needs to be fixed in the next update?
Here is my code:
func areaCalculator(length: Int, width: Int) -> Int {
let area = length * width
return area
}
areaCalculator(length: 8, width: 8)
What I meant for the code to do is to return 64 to the console, since I entered 8 for length and also 8 for width. However, the console is not responding and is showing nothing.
Here is a screenshot:area calculator function, console result, and entry
Another screenshot using rmaddy's method (revised): areaCalculator function, console result, and entry using rmaddy's method
1) Add print statement to print in console
let area = areaCalculator(length: 8, width: 8)
print(area)
2) Repeat the constant to show in the right panel
let area = areaCalculator(length: 8, width: 8)
area

Capture Function keys on Mac OS X

I'm a long-time Objective-C user and slowly migrating towards Swift with new projects. I'm using CocoaPods for the bigger things and can't find a good library to cover this.
So I have this code inside my NSViewController viewDidLoad to start with:
_ = NSEvent.addGlobalMonitorForEventsMatchingMask(NSEventMask.KeyDownMask) {
(event) -> Void in
print("Event is \(event)")
}
let event = NSEvent.keyEventWithType(NSEventType.KeyDown,
location: CGPoint(x:0,y:0),
modifierFlags: NSEventModifierFlags(rawValue: 0),
timestamp: 0.0,
windowNumber: 0,
context: nil,
characters: "\n",
charactersIgnoringModifiers: "",
isARepeat: false,
keyCode: 0) //NSF7FunctionKey
NSApplication.sharedApplication().sendEvent(event!)
So the first event capturing works perfect after having my app checked in the System Preferences' Accessibility list. Anywhere in OS X it will capture key-presses. Now in the docs it says for Function-keys I should use keyEventWithType.
I found this gist and noticed that it addresses the same sharedApplication instance, yet I don't know how to catch the event. Do I delegate in a certain way? Also the F-key constant is int and the method says it only wants to receive Uint16. I can typecast it, but I guess I'm using it wrong.
Fixed it by using a CocoaPods pod that I found later. Works perfectly.

How to automatically color lines in IDA?

I want IDA to automatically color lines in both the graph and text view for important instructions, for example wherever there is a call or xor instruction change the background color of each of those references to a certain color.
Here is what I am looking to achieve:
fig.1 graph view
fig.2 text view
I noticed you can go to Edit > Other > color instruction... from the main menu and this will allow you to change the background color of the selected instruction, but this does not change all of them and seems to only affect the current database.
How can I make IDA automatically color certain instructions such as call and xoras shown from the example images?
I want it to automatically work for any database I open.
You need to write an IDA plug in using IDAPython (python for IDA) or IDC (IDA scripting language which is very similar to C), the following code is in IDC:
#include <idc.idc>
static main(void)
{
auto currentEA;
auto currentMnem;
auto prevMnem;
auto currentOp;
prevMnem = "";
currentOp;
currentEA = FirstSeg();
currentEA = NextHead(currentEA, 0xFFFFFFFF);
while (currentEA != BADADDR)
{
currentMnem = GetMnem(currentEA);
//Highlight call functions
if (currentMnem == "call")
{
SetColor(currentEA, CIC_ITEM, 0xc7c7ff);
}
}
}
You can also refer to the opcodes' operands:
//Non-zeroing XORs are often signs of data encoding
if (currentMnem == "xor")
{
if (GetOpnd(currentEA, 0) != GetOpnd(currentEA, 1))
{
SetColor(currentEA, CIC_ITEM, 0xFFFF00);
}
}
Here is a guide from Hex Blog for using IDC plug-ins.
And here is a sample for similar script in IDA Python instead of IDC.

Automatically open the Safari Debugger when the iPhone Simulator is launched

The iOS web debugger in Safari is the bee's knees, but it closes every time the Simulator is restarted. Not only is it annoying to re-open it from the menu after every build, but it makes it tricky to debug any behavior that happens during startup.
Is there a way to set up a trigger in Xcode to automatically open the Safari debugger after every build, or perhaps a way to build a shell script or Automator action to do a build and immediately open the debugger?
This is a partial solution. This opens the debug window of Safari with one click which is a lot better but not automatic.
Open Script Editor on your mac (Command + Space Bar and type in Script Editor)
Paste in this code:
-- `menu_click`, by Jacob Rus, September 2006
--
-- Accepts a list of form: `{"Finder", "View", "Arrange By", "Date"}`
-- Execute the specified menu item. In this case, assuming the Finder
-- is the active application, arranging the frontmost folder by date.
on menu_click(mList)
local appName, topMenu, r
-- Validate our input
if mList's length < 3 then error "Menu list is not long enough"
-- Set these variables for clarity and brevity later on
set {appName, topMenu} to (items 1 through 2 of mList)
set r to (items 3 through (mList's length) of mList)
-- This overly-long line calls the menu_recurse function with
-- two arguments: r, and a reference to the top-level menu
tell application "System Events" to my menu_click_recurse(r, ((process appName)'s ¬
(menu bar 1)'s (menu bar item topMenu)'s (menu topMenu)))
end menu_click
on menu_click_recurse(mList, parentObject)
local f, r
-- `f` = first item, `r` = rest of items
set f to item 1 of mList
if mList's length > 1 then set r to (items 2 through (mList's length) of mList)
-- either actually click the menu item, or recurse again
tell application "System Events"
if mList's length is 1 then
click parentObject's menu item f
else
my menu_click_recurse(r, (parentObject's (menu item f)'s (menu f)))
end if
end tell
end menu_click_recurse
menu_click({"Safari", "Develop", "Simulator", "index.html"})
Once the simulator has opened, click run on your script (you might need to allow the script editor in the settings the first time).
(Optional) You can save your the scripts as an app so that you don't have to have the script editor open.
There is question that should be marked a duplicate that describes using setTimeout() to give you enough time to switch windows over to Safari and set a breakpoint.
Something like this, where startMyApp is the bootstrap function of your app:
setTimeout(function () {
startMyApp();
}, 20000);
It is super ghetto, but does work. I've submitted a feature request via http://www.apple.com/feedback/safari.html too to close the loop.
Extending upon the #Prisoner's answer, if you use WKWebView you could:
let contentController:WKUserContentController = WKUserContentController()
let pauseForDebugScript = WKUserScript(source: "window.alert(\"Go, turn on Inspector, I'll hold them back!\")",
injectionTime: WKUserScriptInjectionTime.AtDocumentStart,
forMainFrameOnly: true)
contentController.addUserScript(pauseForDebugScript)
let config = WKWebViewConfiguration()
config.userContentController = contentController
//Init browser with configuration (our injected script)
browser = WKWebView(frame: CGRect(x:0, y:0, width: view.frame.width, height: containerView.frame.height), configuration:config)
also important thing is to implement alert handler from WKUIDelegate protocol
//MARK: WKUIDelegate
func webView(webView: WKWebView, runJavaScriptAlertPanelWithMessage message: String,
initiatedByFrame frame: WKFrameInfo, completionHandler: () -> Void) {
let alertController = UIAlertController(title: message, message: nil,
preferredStyle: UIAlertControllerStyle.Alert);
alertController.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.Cancel) {
_ in completionHandler()}
);
self.presentViewController(alertController, animated: true, completion: {});
}
and one little thing just in case you could have an UIAlertController:supportedInterfaceOrientations was invoked recursively error add following extension (From this SO Answer)
extension UIAlertController {
public override func supportedInterfaceOrientations() -> UIInterfaceOrientationMask {
return UIInterfaceOrientationMask.Portrait
}
public override func shouldAutorotate() -> Bool {
return false
}
}
Combining Tom's answer with my solution, first do the following:
Create an application as Tom describes above
In "System Preferences -> Security & Privacy -> Privacy -> Accessibility" add your new Script Applicaiton and make sure it is allowed to control your computer
Now, I'm using cordova and from the command line the following builds, runs emulator and opens safari debug console:
cordova build ios; cordova emulate ios; open /Applications/Xcode.app/Contents/Developer/Applications/Simulator.app; sleep 1 ; open /PATH/TO/OpenDevelop.app/
Make sure to replace /PATH/TO/ with the appropriate path to where you saved your script.
Humm,I don't think you can do that,but you can just "CTRL+R" in the web debugger.