Remove dependencies, improve documentation.
This commit is contained in:
parent
370a2eb604
commit
8ce3b6a6de
160
README.md
160
README.md
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
Create Go language bindings for Objective-C.
|
Create Go language bindings for Objective-C.
|
||||||
|
|
||||||
Using NSWrap, you can easily work with many MacOS interfaces, subclasses,
|
Using NSWrap, you can work with MacOS interfaces, subclasses,
|
||||||
library functions, protocols and delegates entirely in Go.
|
library functions, protocols and delegates entirely in Go.
|
||||||
|
|
||||||
# Getting Started
|
# Getting Started
|
||||||
|
@ -13,20 +13,15 @@ NSWrap runs on MacOS and requires `clang` (from the XCode command line
|
||||||
tools) and the MacOS system header files.
|
tools) and the MacOS system header files.
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
go get git.wow.st/gmp/nswrap/...
|
go get git.wow.st/gmp/nswrap
|
||||||
```
|
```
|
||||||
|
|
||||||
From your `go` source directory, type:
|
The `nswrap` command line tool should now be installed in your `go/bin` path.
|
||||||
|
|
||||||
```sh
|
|
||||||
cd git.wow.st/gmp/nswrap
|
|
||||||
go install
|
|
||||||
```
|
|
||||||
|
|
||||||
Since NSWrap uses `clang` to generate an AST from Objective-C input files, you
|
Since NSWrap uses `clang` to generate an AST from Objective-C input files, you
|
||||||
will need to install XCode and its associated command line tools. Enter
|
will need to install XCode and its associated command line tools. Enter
|
||||||
`clang --version` from your terminal prompt to see if you have it installed
|
`clang --version` from your terminal prompt to see if you have it installed.
|
||||||
already. You will also need to have the Objective-C header files for the
|
You will also need the Objective-C header files for the
|
||||||
various frameworks you want to use. Look for them in
|
various frameworks you want to use. Look for them in
|
||||||
`/System/Library/Frameworks/*/Headers`.
|
`/System/Library/Frameworks/*/Headers`.
|
||||||
|
|
||||||
|
@ -90,8 +85,8 @@ package as your automatically generated bindings.
|
||||||
NSWrap will create bindings for all classes identified in the `classes`
|
NSWrap will create bindings for all classes identified in the `classes`
|
||||||
directive of the configuration file. All of the class and instance methods
|
directive of the configuration file. All of the class and instance methods
|
||||||
are bound to Go and all types identified in the process are wrapped
|
are bound to Go and all types identified in the process are wrapped
|
||||||
in Go types (as described below), except for methods that contain prohibited
|
in Go types (as described below), except for methods that contain unsupported
|
||||||
return types or paramater types (such as blocks and function pointers).
|
return types or paramater types such as blocks and function pointers.
|
||||||
|
|
||||||
```go
|
```go
|
||||||
s1 := ns.NSStringAlloc() // allocate and autorelease an instance of NSString
|
s1 := ns.NSStringAlloc() // allocate and autorelease an instance of NSString
|
||||||
|
@ -106,21 +101,20 @@ with the class name, and, if necessary, disambiguated for overloaded
|
||||||
Objective-C methods. Any redundant initial
|
Objective-C methods. Any redundant initial
|
||||||
characters are elided (e.g. the Objective-C
|
characters are elided (e.g. the Objective-C
|
||||||
`[NSString stringWithString:aString]` is shortened in Go to
|
`[NSString stringWithString:aString]` is shortened in Go to
|
||||||
`ns.NSStringWithString(aString)`). Instance methods are carried over
|
`ns.NSStringWithString(aString)`). Instance methods are converted to
|
||||||
as-is but in TitleCase, and disambiguated for method overloading as described
|
TitleCase and disambiguated for method overloading as described below.
|
||||||
below.
|
|
||||||
|
|
||||||
Note that while return types and parameter types needed for the binding will
|
Note that while return types and parameter types needed for the binding will
|
||||||
be defined and wrapped for you in Go types,
|
be defined and wrapped for you in Go types,
|
||||||
you will not get any of their methods
|
you will not get any of their methods
|
||||||
unless those types also appear in your NSWrap configuration file.
|
unless those types also appear in your NSWrap configuration file.
|
||||||
For example, the `NSDictionaryWithObjects(...)` constructor takes two `NSArray`
|
For example, the `[NSDictionary WithObjects: forKeys:]` constructor takes two
|
||||||
parameters, so if you want to use it you will probably want
|
`NSArray` parameters, so if you want to use it from Go you will probably want
|
||||||
to have `NSArray` in your configuration file in addition to `NSDictionary`.
|
to have `NSArray` in your configuration file in addition to `NSDictionary`.
|
||||||
|
|
||||||
## Overloaded Methods
|
## Overloaded Methods
|
||||||
|
|
||||||
Because Go does not allow overloaded function definitions, NSWrap automatically
|
Because Go does not allow overloaded functions, NSWrap automatically
|
||||||
disambiguates overloaded method names as required.
|
disambiguates overloaded method names as required.
|
||||||
This is done by successively adding parameter names onto the end of the Go
|
This is done by successively adding parameter names onto the end of the Go
|
||||||
function name until a unique name is created.
|
function name until a unique name is created.
|
||||||
|
@ -170,7 +164,7 @@ Go interface.
|
||||||
|
|
||||||
## Working With NSObject and its Descendants
|
## Working With NSObject and its Descendants
|
||||||
|
|
||||||
Objective-C Objects are represented in Go by a type and an interface as
|
Objective-C objects are represented in Go by a type and an interface as
|
||||||
follows:
|
follows:
|
||||||
|
|
||||||
```go
|
```go
|
||||||
|
@ -191,8 +185,8 @@ and therefore implement `NSObject`.
|
||||||
The `Id` type in Go represents the Objective-C type `id`, which is a pointer
|
The `Id` type in Go represents the Objective-C type `id`, which is a pointer
|
||||||
to an Objective-C object. Because `cgo` does not understand this type,
|
to an Objective-C object. Because `cgo` does not understand this type,
|
||||||
NSWrap will always translate it to a `void*` on the C side.
|
NSWrap will always translate it to a `void*` on the C side.
|
||||||
The `NSObject` interface in Go allows any `NS` type to be used with
|
The `NSObject` interface in Go allows any type that directly or indirectly
|
||||||
generic Objective-C functions. For example:
|
embeds `Id` to be used with generic Objective-C functions. For example:
|
||||||
|
|
||||||
```go
|
```go
|
||||||
o1 := ns.NSStringWithGoString("my string")
|
o1 := ns.NSStringWithGoString("my string")
|
||||||
|
@ -202,15 +196,15 @@ a := ns.NSMutableArrayWithObjects(o1,s1)
|
||||||
Since `NSString` and `NSSet` in Go both implement the `NSObject` interface,
|
Since `NSString` and `NSSet` in Go both implement the `NSObject` interface,
|
||||||
they can both be used as parameters to the `NSMutableArray` constructor.
|
they can both be used as parameters to the `NSMutableArray` constructor.
|
||||||
|
|
||||||
This will help you, too, with delegates
|
This will help you, too, when working with delegates
|
||||||
(see below). Classes that accept delegates will generally accept any
|
(see below). Classes that accept delegates will generally accept any
|
||||||
`NSObject` in ther `initWithDelegate()` or `setDelegate()` methods, and
|
`NSObject` in their `initWithDelegate()` or `setDelegate()` methods, and
|
||||||
may or may not test at runtime if the provided object actually
|
may or may not test at runtime if the provided object actually
|
||||||
implements the required delegate protocol.
|
implements the required delegate protocol.
|
||||||
|
|
||||||
* Inheritance
|
* Inheritance
|
||||||
|
|
||||||
Objective-C permits single inheritance. In Go, this is modeled using
|
Objective-C only provides single inheritance. In Go, this is modeled using
|
||||||
embedding. Top level objects that inherit from `NSObject` in Objective-C
|
embedding. Top level objects that inherit from `NSObject` in Objective-C
|
||||||
embed the Go type `Id` and therefore implement the `NSObject` Go interface.
|
embed the Go type `Id` and therefore implement the `NSObject` Go interface.
|
||||||
Other objects embed their superclass. For example:
|
Other objects embed their superclass. For example:
|
||||||
|
@ -245,22 +239,23 @@ receivers. Go will automatically find the indirectly embedded `NSView` and
|
||||||
call the right method.
|
call the right method.
|
||||||
|
|
||||||
Go's type inference appears to be slightly broken (as of 1.12.1) because
|
Go's type inference appears to be slightly broken (as of 1.12.1) because
|
||||||
the following does not work. Look out for this if you are getting type
|
the following does not work. Look out for this if you like to chain your
|
||||||
errors:
|
`Alloc` and `Init` methods and are getting type errors:
|
||||||
|
|
||||||
```go
|
```go
|
||||||
//DO NOT DO THIS
|
//DO NOT DO THIS
|
||||||
b := ns.NSButtonAlloc().InitWithFrame(ns.MakeRect(100,100,200,200))
|
b := ns.NSButtonAlloc().InitWithFrame(ns.MakeRect(100,100,200,200))
|
||||||
//For some reason Go thinks b has type ns.NSView, because InitWithFrame is defined for ns.NSView, even though
|
//For some reason Go thinks b has type ns.NSView, because InitWithFrame is defined for ns.NSView,
|
||||||
//NSButtonAlloc() returns an ns.NSButton.
|
//even though NSButtonAlloc() returns an ns.NSButton.
|
||||||
```
|
```
|
||||||
|
|
||||||
Go has no trouble finding embedded methods for your `NSButton` and will
|
Go has no trouble finding embedded methods for your `NSButton` and will
|
||||||
happily search up the chain through `NSControl`, `NSView`, `NSResponder` and
|
happily search up the chain through `NSControl`, `NSView`, `NSResponder` and
|
||||||
`NSObject` and all of their associated protocols and categories. As of this
|
`NSObject` and all of their associated protocols and categories. As of this
|
||||||
writing, on MacOS 10.13.6, NSWrap binds 90 instance methods for `NSObject`,
|
writing, on MacOS 10.13.6, NSWrap binds 90 instance methods for `NSObject`,
|
||||||
so things like `Hash()`, `IsEqualTo()`, `ClassName()` and many many
|
so things like `Hash()`, `IsEqualTo()`, `ClassName()`, `RespondsToSelector`
|
||||||
others are available and can be called on any object directly from Go.
|
and many many others are available and can be called on any object directly
|
||||||
|
from Go.
|
||||||
|
|
||||||
Go does not perform the same type
|
Go does not perform the same type
|
||||||
magic when you use variables as function or method parameters.
|
magic when you use variables as function or method parameters.
|
||||||
|
@ -271,18 +266,20 @@ an `NSView` type, you need to explicitly pass the embedded `NSView`
|
||||||
NSWrap creates a method for `Id` allowing objects to be converted
|
NSWrap creates a method for `Id` allowing objects to be converted
|
||||||
at run-time to any other class. You will need this for Enumerators, which
|
at run-time to any other class. You will need this for Enumerators, which
|
||||||
always return `Id`. See below under Enumerators for an example, but make
|
always return `Id`. See below under Enumerators for an example, but make
|
||||||
sure you know (or test) what type your objects are before converting them,
|
sure you know (or test) what type your objects are before converting them.
|
||||||
or else you will get an exception from the Objective-C runtime.
|
You can
|
||||||
|
implement a somewhat less convenient version of a Go type switch this way.
|
||||||
|
|
||||||
Because `Id` can be converted to any type, and every object in the Foundation
|
Because `Id` can be converted to any type, and every object in the Foundation
|
||||||
classes inherits from `Id`, it is possible to send any message to any
|
classes inherits from `Id`, it is possible to send any message to any
|
||||||
object, if you are feeling lucky. You are going to have to explicitly
|
object, if you are feeling lucky. If you are not lucky you will get an
|
||||||
|
exception from the Objective-C runtime. You are going to have to explicitly
|
||||||
convert your object to the wrong type before the compiler will let you do this.
|
convert your object to the wrong type before the compiler will let you do this.
|
||||||
|
|
||||||
```go
|
```go
|
||||||
a := ns.NSArrayWithObjects(o1,o2) // NSArray embeds Id
|
a := ns.NSArrayWithObjects(o1,o2) // NSArray embeds Id
|
||||||
fmt.Println(a.NSString().UTF8String()) // DON'T!
|
fmt.Println(a.NSString().UTF8String()) // DON'T!
|
||||||
// | | \-method of NSString, returns *Char, a "Stringer" type
|
// | | \-method of NSString, returns *Char, a "Stringer"
|
||||||
// | \-method of Id returning NSString
|
// | \-method of Id returning NSString
|
||||||
// \-calls "String()" on its parameters
|
// \-calls "String()" on its parameters
|
||||||
```
|
```
|
||||||
|
@ -301,22 +298,28 @@ As seen above with the `NSMutableArrayWithObjects()` constructor example,
|
||||||
NSWrap supports variadic
|
NSWrap supports variadic
|
||||||
functions. Because of the limitations of `cgo`, there is a numerical limit
|
functions. Because of the limitations of `cgo`, there is a numerical limit
|
||||||
to the number of parameters in a variadic function call, which defaults to
|
to the number of parameters in a variadic function call, which defaults to
|
||||||
16 but can be set with the `vaargs` configuration directive.
|
16 but can be set with the `vaargs` configuration directive. NSWrap will
|
||||||
|
automatically include a `nil` sentinel before calling any Objective-C
|
||||||
|
methods with variadic parameter lists. The direct types `va_list` and
|
||||||
|
`va_list_tag` are not currently supported.
|
||||||
|
|
||||||
## Pointers to Pointers
|
## Pointers to Pointers
|
||||||
|
|
||||||
When NSWrap encounters a pointer to a pointer to an Objective-C object, it
|
When NSWrap encounters a pointer to a pointer to an Objective-C object, it
|
||||||
treats it as an array of objects and translates it into a pointer to a
|
treats it as an array of objects and translates it into a pointer to a
|
||||||
Go slice. If you are passing empty slices into these functions, be sure to
|
Go slice. If you are passing empty slices into these functions, be sure to
|
||||||
pre-allocate them to a sufficient size and capacity (see below for an
|
pre-allocate them to a sufficient capacity. Ssee below for an
|
||||||
example). These Go slices can be used for input and output of methods and
|
example. These Go slices can be used for input and output of methods and
|
||||||
functions.
|
functions.
|
||||||
|
|
||||||
Pointers to pointers are sometimes passed to Objective-C methods or functions
|
Pointers to pointers are sometimes passed to Objective-C methods or functions
|
||||||
as a way of receiving output from those functions. In those cases, after the
|
as a way of receiving output from those functions, especially because
|
||||||
CGo call, the method parameter is treated as a nil-terminated array of object
|
Objective-C does not allow for multiple return values. In those cases, after
|
||||||
pointers. The object pointers are copied into the input Go slice, which is
|
the CGo call, the method parameter will be treated as a nil-terminated array of
|
||||||
then truncated to the appropriate length.
|
object pointers that may have been modified by the Objective-C function or
|
||||||
|
method. NSWrap will copy the object pointers back into the input Go slice, up
|
||||||
|
to its capacity (which will never be changed). The input Go slice is then
|
||||||
|
truncated to the appropriate length.
|
||||||
|
|
||||||
An example in Core Foundation is the `getObjects:andKeys:count` method for
|
An example in Core Foundation is the `getObjects:andKeys:count` method for
|
||||||
`NSDictionary`:
|
`NSDictionary`:
|
||||||
|
@ -328,16 +331,21 @@ An example in Core Foundation is the `getObjects:andKeys:count` method for
|
||||||
ns.NSArrayWithObjects(nst("key1"),nst("key2")),
|
ns.NSArrayWithObjects(nst("key1"),nst("key2")),
|
||||||
)
|
)
|
||||||
os,ks := make([]ns.Id,0,5), make([]ns.Id,0,5) // length 0, capacity 5 slices
|
os,ks := make([]ns.Id,0,5), make([]ns.Id,0,5) // length 0, capacity 5 slices
|
||||||
dict.GetObjects(&os,&ks,5) // count = 5, must be the same size or smaller than the input slice capacity
|
dict.GetObjects(&os,&ks,5)
|
||||||
|
// last parameter is the count, must be less than or equal to the input slice capacity
|
||||||
fmt.Printf("Length of os is now %d\n",len(os)) // os and ks slices are now length = 2
|
fmt.Printf("Length of os is now %d\n",len(os)) // os and ks slices are now length = 2
|
||||||
for i,k := range ks {
|
for i,k := range ks {
|
||||||
fmt.Printf("-- %s -> %s\n",k.NSString(),os[i].NSString())
|
fmt.Printf("-- %s -> %s\n",k.NSString(),os[i].NSString())
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
NSWrap will never check the "count" parameter, so the user will always need
|
||||||
|
to make sure it is less than or equal to the capacity of the relevant input
|
||||||
|
Go slices.
|
||||||
|
|
||||||
Using pointers to pointers is necessary in many Core Foundation situations
|
Using pointers to pointers is necessary in many Core Foundation situations
|
||||||
where you need to get an error message out of a function or method, for example
|
where you need to get an error message out of a function or method.
|
||||||
in `[NSString stringWithContentsOfURL...]`:
|
Here is an example using `[NSString stringWithContentsOfURL...]`:
|
||||||
|
|
||||||
```go
|
```go
|
||||||
err := make([]ns.NSError,1)
|
err := make([]ns.NSError,1)
|
||||||
|
@ -422,14 +430,21 @@ const _CLOCK_MONOTONIC_RAW = C._CLOCK_MONOTONIC_RAW
|
||||||
|
|
||||||
## Memory management
|
## Memory management
|
||||||
|
|
||||||
You can call `Retain()`, `Release()` and `Autorelease()` on any object.
|
Objective-C objects are always allocated and returned from CGo code, and
|
||||||
|
therefore these pointers are not garbage collected by Go. You can use any
|
||||||
|
of the standard Objective-C memory management techniques for those pointers,
|
||||||
|
which seem to work but have not been extensively tested.
|
||||||
|
|
||||||
All allocation functions generated by NSWrap call `autorelease` before they
|
Since everything inherits methods from `NSObject`, you can call `Retain()`,
|
||||||
return an object. If you are not working in an environment (such as an
|
`Release()` and `Autorelease()` on any object.
|
||||||
|
|
||||||
|
All allocation functions created by NSWrap (i.e. those ending in `Alloc`)
|
||||||
|
call `autorelease` before they return an object.
|
||||||
|
If you are not working in an environment (such as an
|
||||||
Application Delegate callback) that provides an autorelease pool, you can
|
Application Delegate callback) that provides an autorelease pool, you can
|
||||||
create your own:
|
create your own:
|
||||||
|
|
||||||
* Work directly with NSAutoreleasePool objects
|
* Work directly with `NSAutoreleasePool` objects
|
||||||
|
|
||||||
```go
|
```go
|
||||||
swamp := ns.NSAutoreleasePoolAlloc().Init()
|
swamp := ns.NSAutoreleasePoolAlloc().Init()
|
||||||
|
@ -440,7 +455,7 @@ str := ns.NSStringWithGoString("these objects will be automatically deallocated
|
||||||
swamp.Drain()
|
swamp.Drain()
|
||||||
```
|
```
|
||||||
|
|
||||||
* ...or use the AutoreleasePool() helper function
|
* ...or use the `AutoreleasePool()` helper function
|
||||||
|
|
||||||
NSWrap provides a helper function that can be passed a `func()` with no
|
NSWrap provides a helper function that can be passed a `func()` with no
|
||||||
parameters or return value. It is conventient to give it an anonymous function
|
parameters or return value. It is conventient to give it an anonymous function
|
||||||
|
@ -492,25 +507,27 @@ delegates:
|
||||||
...
|
...
|
||||||
```
|
```
|
||||||
|
|
||||||
The generated delegate inherits from NSObject and is identified as implementing
|
The generated delegate inherits from `NSObject` and, in its interface
|
||||||
the protocols specified in `nswrap.yaml`.
|
declaration, is advertised as implementing the protocols specified in
|
||||||
|
`nswrap.yaml`.
|
||||||
|
|
||||||
When a delegate is activated and one of the callback methods named in the
|
When a delegate is activated and one of the callback methods named in the
|
||||||
configuration file is called, the delegate will call back into an exported Go
|
configuration file is called, the delegate will call back into a Go
|
||||||
function. If a user-defined callback function has been specified,
|
function exported by NSWrap. If a user-defined callback function has been
|
||||||
|
specified,
|
||||||
it will be called with all of its parameters converted to their Go type
|
it will be called with all of its parameters converted to their Go type
|
||||||
equivalents. User-defined callbacks are registered by calling a function
|
equivalents. User-defined callbacks are registered by calling a function
|
||||||
with the method name in TitleCase + `Callback`, so in the example above,
|
with the method name in TitleCase + `Callback`, so in the example above,
|
||||||
call `ns.CentralManagerDidUpdateStateCallback(...)` with the name of your
|
you would call `ns.CentralManagerDidUpdateStateCallback(...)` with the name of
|
||||||
callback function to register to receive notifications when your central
|
your callback function to register to receive notifications when your central
|
||||||
manager updates its state.
|
manager updates its state.
|
||||||
|
|
||||||
The code in `examples/bluetooth` implements a working Bluetooth Low Energy
|
The example in `examples/bluetooth` implements a working Bluetooth Low-Energy
|
||||||
heart rate monitor entirely in Go.
|
heart rate monitor entirely in Go.
|
||||||
|
|
||||||
The following Go code creates a CBDelegate object in Go,
|
The following Go code instantiates a `CBDelegate` object,
|
||||||
registers a callback for `centralManagerDidUpdateState`, allocates
|
registers a callback for `centralManagerDidUpdateState`, allocates
|
||||||
a CBCentralManager object, and installs our delegate:
|
a `CBCentralManager` object, and installs our delegate:
|
||||||
|
|
||||||
```go
|
```go
|
||||||
func cb(c ns.CBCentralManager) {
|
func cb(c ns.CBCentralManager) {
|
||||||
|
@ -541,15 +558,15 @@ type for the callback is `func(ns.NSNotification)` with no return value.
|
||||||
|
|
||||||
## Working with AppKit
|
## Working with AppKit
|
||||||
|
|
||||||
You can wrap the AppKit framework classes and create an NSApplication
|
You can wrap the AppKit framework classes and create an `NSApplication`
|
||||||
Delegate. This allows you to build a Cocoa app entirely in Go.
|
Delegate. This allows you to build a Cocoa application entirely in Go.
|
||||||
|
|
||||||
Because AppKit uses thread local storage, you will need to make sure all
|
Because AppKit uses thread local storage, you will need to make sure all
|
||||||
calls into it are done from the main OS thread. This can be a challenge in
|
calls into it are done from the main OS thread. This can be a challenge in
|
||||||
Go even though runtime.LockOSThread() is supposed to provide
|
Go even though runtime.LockOSThread() is supposed to provide
|
||||||
this functionality. Good luck with that!
|
this functionality.
|
||||||
|
|
||||||
This is actually a full working example:
|
This is actually a full working Cocoa application:
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
# nswrap.yaml
|
# nswrap.yaml
|
||||||
|
@ -585,7 +602,7 @@ package main
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"runtime"
|
"runtime"
|
||||||
"git.wow.st/gmp/nswrap/examples/app/ns" // point to your NSWrap output directory
|
"git.wow.st/gmp/nswrap/examples/app/ns" // point to your own NSWrap output directory
|
||||||
)
|
)
|
||||||
|
|
||||||
func didFinishLaunching(n ns.NSNotification) {
|
func didFinishLaunching(n ns.NSNotification) {
|
||||||
|
@ -619,7 +636,7 @@ func main() {
|
||||||
|
|
||||||
Pretty simple right? Not really, NSWrap just generated almost 15,000 lines of
|
Pretty simple right? Not really, NSWrap just generated almost 15,000 lines of
|
||||||
code. See `examples/app` for a slightly more complex example with working
|
code. See `examples/app` for a slightly more complex example with working
|
||||||
menus and visual format-based auto layout.
|
menus, visual format-based auto layout, and a custom button class.
|
||||||
|
|
||||||
## Subclasses
|
## Subclasses
|
||||||
|
|
||||||
|
@ -637,7 +654,7 @@ subclasses:
|
||||||
yourClass: # the superclass to inherit from
|
yourClass: # the superclass to inherit from
|
||||||
- init.* # what methods to override
|
- init.* # what methods to override
|
||||||
- -(void)hi_there:(int)x # Objective-C prototype of your new method(s)
|
- -(void)hi_there:(int)x # Objective-C prototype of your new method(s)
|
||||||
# |--note the hyphen indicating that this is an instance method
|
# |--this hyphen indicates that this is an instance method
|
||||||
```
|
```
|
||||||
|
|
||||||
In the example above, your new class will be named `myClass` in Objective-C
|
In the example above, your new class will be named `myClass` in Objective-C
|
||||||
|
@ -652,6 +669,17 @@ name, its return type, and the names and types of its parameters if any.
|
||||||
Since multiple inheritance is not permitted in Objective-C, it is not possible
|
Since multiple inheritance is not permitted in Objective-C, it is not possible
|
||||||
to specify more than one superclass in a `subclasses` entry.
|
to specify more than one superclass in a `subclasses` entry.
|
||||||
|
|
||||||
|
Go callbacks for subclasses are passed a special struct named "super" as their
|
||||||
|
first parameter. This struct is filled with superclass methods, which
|
||||||
|
allows you to do things like this:
|
||||||
|
|
||||||
|
```go
|
||||||
|
func methodCallback(super ns.MyClassSupermethods, param NSString) {
|
||||||
|
...
|
||||||
|
super.Method(param)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
You can use subclasses to define new AppKit controls with configurable
|
You can use subclasses to define new AppKit controls with configurable
|
||||||
callbacks. For example, lets make an `NSButton` that calls back into Go when
|
callbacks. For example, lets make an `NSButton` that calls back into Go when
|
||||||
you press it:
|
you press it:
|
||||||
|
@ -683,7 +711,7 @@ func didFinishLaunching(n ns.NSNotification) {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Later on you can add the your new button to a view and tell Cocoa where to lay
|
Later on you can add your new button to a view and tell Cocoa where to lay
|
||||||
it out. It's all a little verbose, but that's because for some reason you
|
it out. It's all a little verbose, but that's because for some reason you
|
||||||
decided to write Objective-C code in Go.
|
decided to write Objective-C code in Go.
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@ package ast
|
||||||
import (
|
import (
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/elliotchance/c2go/util"
|
"git.wow.st/gmp/nswrap/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
// AllocSizeAttr is a type of attribute that is optionally attached to a variable
|
// AllocSizeAttr is a type of attribute that is optionally attached to a variable
|
||||||
|
|
|
@ -4,7 +4,7 @@ import (
|
||||||
"reflect"
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/elliotchance/c2go/util"
|
"git.wow.st/gmp/nswrap/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestArrayFiller(t *testing.T) {
|
func TestArrayFiller(t *testing.T) {
|
||||||
|
|
|
@ -5,7 +5,7 @@ import (
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/elliotchance/c2go/util"
|
"git.wow.st/gmp/nswrap/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
var TrackPositions bool = false
|
var TrackPositions bool = false
|
||||||
|
|
|
@ -6,7 +6,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/elliotchance/c2go/util"
|
"git.wow.st/gmp/nswrap/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
func formatMultiLine(o interface{}) string {
|
func formatMultiLine(o interface{}) string {
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
package ast
|
package ast
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/elliotchance/c2go/util"
|
"git.wow.st/gmp/nswrap/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
// CharacterLiteral is type of character literal
|
// CharacterLiteral is type of character literal
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
package ast
|
package ast
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/elliotchance/c2go/util"
|
"git.wow.st/gmp/nswrap/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ConstantArrayType is constant array type
|
// ConstantArrayType is constant array type
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
package ast
|
package ast
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
//"errors"
|
||||||
"fmt"
|
//"fmt"
|
||||||
"reflect"
|
//"reflect"
|
||||||
|
|
||||||
"github.com/elliotchance/c2go/cc"
|
//"github.com/elliotchance/c2go/cc"
|
||||||
)
|
)
|
||||||
|
|
||||||
// FloatingLiteral is type of float literal
|
// FloatingLiteral is type of float literal
|
||||||
|
@ -63,6 +63,7 @@ type FloatingLiteralError struct {
|
||||||
Err error
|
Err error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* NOT USED
|
||||||
// RepairFloatingLiteralsFromSource finds the exact values of floating literals
|
// RepairFloatingLiteralsFromSource finds the exact values of floating literals
|
||||||
// by reading their values directly from the preprocessed source.
|
// by reading their values directly from the preprocessed source.
|
||||||
//
|
//
|
||||||
|
@ -111,4 +112,4 @@ func RepairFloatingLiteralsFromSource(rootNode Node, preprocessedFile string) []
|
||||||
}
|
}
|
||||||
|
|
||||||
return errs
|
return errs
|
||||||
}
|
}*/
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
package ast
|
package ast
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/elliotchance/c2go/util"
|
"git.wow.st/gmp/nswrap/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
// FormatAttr is a type of attribute that is optionally attached to a variable
|
// FormatAttr is a type of attribute that is optionally attached to a variable
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
package ast
|
package ast
|
||||||
|
|
||||||
import "github.com/elliotchance/c2go/util"
|
import "git.wow.st/gmp/nswrap/util"
|
||||||
|
|
||||||
// MaxFieldAlignmentAttr is a type of attribute that is optionally attached to a variable
|
// MaxFieldAlignmentAttr is a type of attribute that is optionally attached to a variable
|
||||||
// or struct field definition.
|
// or struct field definition.
|
||||||
|
|
|
@ -3,7 +3,7 @@ package ast
|
||||||
import (
|
import (
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/elliotchance/c2go/util"
|
"git.wow.st/gmp/nswrap/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
// NonNullAttr is a type of attribute that is optionally attached to a variable
|
// NonNullAttr is a type of attribute that is optionally attached to a variable
|
||||||
|
|
|
@ -4,7 +4,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
|
||||||
"github.com/elliotchance/c2go/util"
|
"git.wow.st/gmp/nswrap/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Position is type of position in source code
|
// Position is type of position in source code
|
||||||
|
|
|
@ -3,7 +3,7 @@ package ast
|
||||||
import (
|
import (
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/elliotchance/c2go/util"
|
"git.wow.st/gmp/nswrap/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
// SentinelAttr is a type of attribute that is optionally attached to a variable
|
// SentinelAttr is a type of attribute that is optionally attached to a variable
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
package ast
|
package ast
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/elliotchance/c2go/util"
|
"git.wow.st/gmp/nswrap/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
// VectorType is vector type
|
// VectorType is vector type
|
||||||
|
|
|
@ -96,6 +96,8 @@ func didFinishLaunching(n ns.NSNotification) {
|
||||||
cv.AddConstraints(ns.NSLayoutConstraintsWithVisualFormat(
|
cv.AddConstraints(ns.NSLayoutConstraintsWithVisualFormat(
|
||||||
nst("H:[b1]-[b2]"),ns.NSLayoutFormatAlignAllBaseline,
|
nst("H:[b1]-[b2]"),ns.NSLayoutFormatAlignAllBaseline,
|
||||||
ns.NSDictionary{}, viewmap))
|
ns.NSDictionary{}, viewmap))
|
||||||
|
|
||||||
|
a.ActivateIgnoringOtherApps(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
func shouldTerminateAfterLastWindowClosed(s ns.NSApplication) ns.BOOL {
|
func shouldTerminateAfterLastWindowClosed(s ns.NSApplication) ns.BOOL {
|
||||||
|
|
2
main.go
2
main.go
|
@ -256,7 +256,7 @@ func main() {
|
||||||
|
|
||||||
confbytes, err := ioutil.ReadFile("nswrap.yaml")
|
confbytes, err := ioutil.ReadFile("nswrap.yaml")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("Cannot open config file nswrap.yaml. %s\n",err)
|
fmt.Printf("%s\n\nFATAL ERROR: Configuration file must be present in directory where nswrap\nis invoked.\n",err)
|
||||||
os.Exit(-1)
|
os.Exit(-1)
|
||||||
}
|
}
|
||||||
if err = yaml.Unmarshal(confbytes,&Config); err != nil {
|
if err = yaml.Unmarshal(confbytes,&Config); err != nil {
|
||||||
|
|
19
util/errors.go
Normal file
19
util/errors.go
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
package util
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
// PanicIfNil will panic with the message provided if the check is nil. This is
|
||||||
|
// a convieniance method to avoid many similar if statements.
|
||||||
|
func PanicIfNil(check interface{}, message string) {
|
||||||
|
if check == nil {
|
||||||
|
panic(message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// PanicOnError will panic with the message and error if the error is not nil.
|
||||||
|
// If the error is nil (no error) then nothing happens.
|
||||||
|
func PanicOnError(err error, message string) {
|
||||||
|
if err != nil {
|
||||||
|
panic(fmt.Sprintf("%s: %s", message, err.Error()))
|
||||||
|
}
|
||||||
|
}
|
57
util/regexp.go
Normal file
57
util/regexp.go
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
package util
|
||||||
|
|
||||||
|
import (
|
||||||
|
"regexp"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
// GroupsFromRegex gets RegExp groups after matching it on a line
|
||||||
|
func GroupsFromRegex(rx, line string) map[string]string {
|
||||||
|
// We remove tabs and newlines from the regex. This is purely cosmetic,
|
||||||
|
// as the regex input can be quite long and it's nice for the caller to
|
||||||
|
// be able to format it in a more readable way.
|
||||||
|
rx = strings.Replace(rx, "\r", "", -1)
|
||||||
|
rx = strings.Replace(rx, "\n", "", -1)
|
||||||
|
rx = strings.Replace(rx, "\t", "", -1)
|
||||||
|
re := GetRegex(rx)
|
||||||
|
|
||||||
|
match := re.FindStringSubmatch(line)
|
||||||
|
if len(match) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
result := make(map[string]string)
|
||||||
|
for i, name := range re.SubexpNames() {
|
||||||
|
if i != 0 {
|
||||||
|
result[name] = match[i]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
// cachedRegex - structure for saving regexp`s
|
||||||
|
type cachedRegex struct {
|
||||||
|
sync.RWMutex
|
||||||
|
m map[string]*regexp.Regexp
|
||||||
|
}
|
||||||
|
|
||||||
|
// Global variable
|
||||||
|
var cr = cachedRegex{m: map[string]*regexp.Regexp{}}
|
||||||
|
|
||||||
|
// GetRegex return regexp
|
||||||
|
// added for minimaze regexp compilation
|
||||||
|
func GetRegex(rx string) *regexp.Regexp {
|
||||||
|
cr.RLock()
|
||||||
|
v, ok := cr.m[rx]
|
||||||
|
cr.RUnlock()
|
||||||
|
if ok {
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
// if regexp is not in map
|
||||||
|
cr.Lock()
|
||||||
|
cr.m[rx] = regexp.MustCompile(rx)
|
||||||
|
cr.Unlock()
|
||||||
|
return GetRegex(rx)
|
||||||
|
}
|
40
util/test.go
Normal file
40
util/test.go
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
package util
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"math"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ShowDiff will print two strings vertically next to each other so that line
|
||||||
|
// differences are easier to read.
|
||||||
|
func ShowDiff(a, b string) string {
|
||||||
|
aLines := strings.Split(a, "\n")
|
||||||
|
bLines := strings.Split(b, "\n")
|
||||||
|
maxLines := int(math.Max(float64(len(aLines)), float64(len(bLines))))
|
||||||
|
out := "\n"
|
||||||
|
|
||||||
|
for lineNumber := 0; lineNumber < maxLines; lineNumber++ {
|
||||||
|
aLine := ""
|
||||||
|
bLine := ""
|
||||||
|
|
||||||
|
// Replace NULL characters with a dot. Otherwise the strings will look
|
||||||
|
// exactly the same but have different length (and therfore not be
|
||||||
|
// equal).
|
||||||
|
if lineNumber < len(aLines) {
|
||||||
|
aLine = strconv.Quote(aLines[lineNumber])
|
||||||
|
}
|
||||||
|
if lineNumber < len(bLines) {
|
||||||
|
bLine = strconv.Quote(bLines[lineNumber])
|
||||||
|
}
|
||||||
|
|
||||||
|
diffFlag := " "
|
||||||
|
if aLine != bLine {
|
||||||
|
diffFlag = "*"
|
||||||
|
}
|
||||||
|
out += fmt.Sprintf("%s %3d %-40s%-40s\n", diffFlag, lineNumber+1, aLine, bLine)
|
||||||
|
}
|
||||||
|
|
||||||
|
return out
|
||||||
|
}
|
62
util/util.go
Normal file
62
util/util.go
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
package util
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// InStrings returns true if item exists in items. It must be an exact string
|
||||||
|
// match.
|
||||||
|
func InStrings(item string, items []string) bool {
|
||||||
|
for _, v := range items {
|
||||||
|
if item == v {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ucfirst returns the word with the first letter uppercased; none of the other
|
||||||
|
// letters in the word are modified. For example "fooBar" would return "FooBar".
|
||||||
|
func Ucfirst(word string) string {
|
||||||
|
if word == "" {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(word) == 1 {
|
||||||
|
return strings.ToUpper(word)
|
||||||
|
}
|
||||||
|
|
||||||
|
return strings.ToUpper(string(word[0])) + word[1:]
|
||||||
|
}
|
||||||
|
|
||||||
|
// Atoi converts a string to an integer in cases where we are sure that s will
|
||||||
|
// be a valid integer, otherwise it will panic.
|
||||||
|
func Atoi(s string) int {
|
||||||
|
i, err := strconv.Atoi(s)
|
||||||
|
PanicOnError(err, "bad integer")
|
||||||
|
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetExportedName returns a deterministic and Go safe name for a C type. For
|
||||||
|
// example, "*__foo[]" will return "FooSlice".
|
||||||
|
func GetExportedName(field string) string {
|
||||||
|
if strings.Contains(field, "interface{}") ||
|
||||||
|
strings.Contains(field, "Interface{}") {
|
||||||
|
return "Interface"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert "[]byte" into "byteSlice". This also works with multiple slices,
|
||||||
|
// like "[][]byte" to "byteSliceSlice".
|
||||||
|
for len(field) > 2 && field[:2] == "[]" {
|
||||||
|
field = field[2:] + "Slice"
|
||||||
|
}
|
||||||
|
|
||||||
|
// NotFunc(int)()
|
||||||
|
field = strings.Replace(field, "(", "_", -1)
|
||||||
|
field = strings.Replace(field, ")", "_", -1)
|
||||||
|
|
||||||
|
return Ucfirst(strings.TrimLeft(field, "*_"))
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user