Have breakpoint print the name of the calling function - swift

I'd like to have my breakpoint print the name of the test it's being called from in the console. Is this possible?
Relatedly, can I have a breakpoint condition be dependent on which function got us to the breakpoint?

While not exactly the "function" name you can use lldb's command to print the call stack as far back as you want.
In Xcode create a breakpoint with a "Debugger Command" action of bt 2 (the 2 limits the depth of the call stack to print). If you don't want the breakpoint to actually stop processing also tick the option "Automatically continue…" checkbox at the bottom.
When the breakpoint is hit you'll see output similar to this in the "Debugger Output" pane in the "Debug Area" at the bottom of your Xcode window.
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1
* frame #0: 0x0000000104982fa8 SharingTest`DataManager.loadFromDisk(self=0x000060800005e3f0) at DataManager.swift:66
frame #1: 0x0000000104998dbe SharingTest`AppDelegate.applicationDidBecomeActive(application=0x00007fe6b9600220, self=0x000060400005b2d0) at AppDelegate.swift:56

If you add a string parameter with a default value of #function, it gets filled in with the calling function name:
func bar(_ funcName:String = #function) {
print("called from function", funcName)
}
func foo() {
bar()
}
foo()
That prints "called from function foo()"
The only problem with that is if you pass it an actual string value, that overrides the default value so:
func foo() {
bar("snort")
}
That prints "called from function snort"

Related

in vscode default formatter for JavaScript, how to avoid space before brace?

here is my code
function foo(){
}
after passing it through the default formatter(alt+shift+f) I get:
function foo() {
}
(note the added space in the first line)
My question is: how do I set up the formatter so it does not add the space?

Async dispatch inside a function - compiler getting too aggressive?

Ran across an interesting one today. Loading up a window controller that I pop up for some task-specific UI stuff. I was just working on the actual window layout dynamics, and wanted to suppress the loading of a configured view controller into one of the views - Just slapped a "return" in the load-up function, thinking that it would exit the function before the async call to load the VC.
func setContainer( container:ListContainer ){
self.container = container
return
DispatchQueue.main.async {
// return
let vs = ListsViewController()
vs.setLists(lists: self.container.itemLists)
vs.view.frame = CGRect(x: 0, y: 0, width: self.listsBox.frame.width, height: self.listsBox.frame.height)
self.listsBox.subviews.removeAll()
self.listsBox.addSubview(vs.view)
}
}
Interestingly, with that first return in there, the stuff inside the async call still executed, like the compiler is saying "that return doesn't apply to the async call because I said so."
The (currently commented out) return inside the async block does exactly the right thing, but I thought it odd that the async block would still run, with appearing after the return. Am I nuts?
macOS Catalina,
macOS application,
Xcode 12.0.1,
Swift 5 (presumably)
This is expected. Your function returns Void, a type that has a single value (). DispatchQueue.main.async also returns Void. With your return you are returning the result of DispatchQueue.main.async (which is again ()). As matt suggested in the comments add a ; after return.

MacOS Quartz Event Tap listening to wrong events

I am trying to intercept mouse move events using the CGEvent.tapCreate(tap:place:options:eventsOfInterest:callback:userInfo:) method as shown below:
let cfMachPort = CGEvent.tapCreate(tap: CGEventTapLocation.cghidEventTap,
place: CGEventTapPlacement.headInsertEventTap,
options: CGEventTapOptions.defaultTap,
eventsOfInterest:CGEventMask(CGEventType.mouseMoved.rawValue),
callback: {(eventTapProxy, eventType, event, mutablePointer) -> Unmanaged<CGEvent>? in event
print(event.type.rawValue) //Breakpoint
return nil
}, userInfo: nil)
let runloopSource = CFMachPortCreateRunLoopSource(kCFAllocatorDefault, cfMachPort!, 0)
let runLoop = RunLoop.current
let cfRunLoop = runLoop.getCFRunLoop()
CFRunLoopAddSource(cfRunLoop, runloopSource, CFRunLoopMode.defaultMode)
I pass as event type eventsOfInterest mouseMoved events with a raw value of 5 as seen in the documentation. But for some reason my print() is not executed unless I click with the mouse. Inspecting the send mouse event in the debugger gives me a raw value of 2, which according to the documentation is a leftMouseUp event.
In the documentation for CGEvent.tapCreate(tap:place:options:eventsOfInterest:callback:userInfo:) it says:
Event taps receive key up and key down events [...]
So it seems like the method ignores mouseMoved events in general?! But how am I supposed to listen to mouseMoved events? I am trying to prevent my cursor (custom cursor) from being replaced (for example when I hover over the application dock at the bottom of the screen).
You need to bitshift the CGEventType value used to create the CGEventMask parameter. In Objective-C, there is a macro to do this: CGEventMaskBit.
From the CGEventMask documentation:
to form the bit mask, use the CGEventMaskBit macro to convert each constant into an event mask and then OR the individual masks together
I don't know the equivalent mechanism in swift; but the macro itself looks like this:
*/ #define CGEventMaskBit(eventType) ((CGEventMask)1 << (eventType))
In your example, it's sufficient to just manually shift the argument; e.g.
eventsOfInterest:CGEventMask(1 << CGEventType.mouseMoved.rawValue),
I would point out that the code example given in the question is a little dangerous; as it creates a default event tap and then drops the events rather than allowing them to be processed. This messes up mouse click handling and it was tricky to actually terminate the application using the mouse. Anyone running the example could set the event tap type to CGEventTapOptions.listenOnly to prevent that.
Here is a way to listen for mouseMove global events (tested with Xcode 11.2+, macOS 10.15)
// ... say in AppDelegate
var globalObserver: Any!
var localObserver: Any!
func applicationDidFinishLaunching(_ aNotification: Notification) {
globalObserver = NSEvent.addGlobalMonitorForEvents(matching: .mouseMoved) { event in
let location = event.locationInWindow
print("in background: {\(location.x), \(location.y)}")
}
localObserver = NSEvent.addLocalMonitorForEvents(matching: .mouseMoved) { event in
let location = event.locationInWindow
print("active: {\(location.x), \(location.y)}")
return event
}
...
There's another thing incorrect in your code, although you might be lucky and it isn't normally causing a problem.
As documented for the mode parameter to CFRunLoopAddSource: "Use the constant kCFRunLoopCommonModes to add source to the set of objects monitored by all the common modes."
That third parameter should instead be CFRunLoopMode.commonModes.
What you have, CFRunLoopMode.defaultMode aka kCFRunLoopDefaultMode, is instead for use when calling CFRunLoopRun.

How do I connect a custom function to the clicked action of a GTK Button?

I am working my way through the Vala GTK+3 tutorial provided by Elementary OS. I understand that this code:
var button_hello = new Gtk.Button.with_label ("Click me!");
button_hello.clicked.connect (() => {
button_hello.label = "Hello World!";
button_hello.set_sensitive (false);
});
uses a Lambda function to change the button's label when it's clicked. What I want to do is call this function instead:
void clicked_button(Gtk.Button sender) {
sender.label = "Clicked. Yippee!";
sender.set_sensitive(false);
}
I've tried this:
button.clicked.connect(clicked_button(button));
But I get this error from the Vala compile when I try to compile:
hello-packaging.vala:16.25-16.46: error: invocation of void method not allowed as expression
button.clicked.connect(clicked_button(button));
^^^^^^^^^^^^^^^^^^^^^^
Compilation failed: 1 error(s), 0 warning(s)
I'm new to both Vala and Linux so please be gentle but can someone point me in the right direction?
You need to pass a reference to the function, rather than the result of the function. So it should be:
button.clicked.connect (clicked_button);
When the button is clicked GTK+ will invoke the clicked_button function with the button as an argument.
The error message invocation of void method not allowed as expression is telling you you are calling (invoking) the method and it has no result (void). Adding parentheses, (), to the end of a function name invokes that function.
Managed to get it working. Here's the code in case others need it:
int main(string[] args) {
// Initialise GTK
Gtk.init(ref args);
// Configure our window
var window = new Gtk.Window();
window.set_default_size(350, 70);
window.title = "Hello Packaging App";
window.set_position(Gtk.WindowPosition.CENTER);
window.set_border_width(12);
window.destroy.connect(Gtk.main_quit);
// Create our button
var button = new Gtk.Button.with_label("Click Me!");
button.clicked.connect(clicked_button);
// Add the button to the window
window.add(button);
window.show_all();
// Start the main application loop
Gtk.main();
return 0;
}
// Handled the clicking of the button
void clicked_button(Gtk.Button sender) {
sender.label = "Clicked. Yippee!";
sender.set_sensitive(false);
}

Can I use the eclipse debugger to write a variable to a file

Is it possible to create some sort of "trace breakpoint" in eclipse whereby Eclipse will log variables that I choose to a file when a "breakpoint" is hit without pausing the application?
Sure. For this sample method:
public static void logArgs(final String one, final String two) {
System.out.println(one + two);
}
put your breakpoint in it, right click it and edit Breakpoint properties... as in the example. The important checkboxes are Conditional and Suspend when 'true'. Just return false so that breakpoint does not suspend at all.
java.io.FileWriter w = new java.io.FileWriter("/tmp/file.txt", true);
w.write(String.format("args(%s, %s)%n"), one, two));
w.close();
return false;
For Java 11 Michał Grzejszczak's answer can be written as
java.nio.file.Files.writeString(java.nio.file.Path.of("f.txt"), "My string to save");return true;
(Best way to write String to file using java nio)