Skip to content

Commit e0f63e2

Browse files
committed
move FFI code into separate crate
1 parent 220a105 commit e0f63e2

File tree

10 files changed

+194
-172
lines changed

10 files changed

+194
-172
lines changed

.gitignore

+3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
xi-modal-input/Cargo.lock
22
xi-modal-input/target
33

4+
xi-ffi/Cargo.lock
5+
xi-ffi/target
6+
47
ModalInputTest/*.a
58

69
### macOS ###

ModalInputTest/ModalInputTest.xcodeproj/project.pbxproj

+3-3
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@
3737
/* End PBXContainerItemProxy section */
3838

3939
/* Begin PBXFileReference section */
40-
603608D2224EC693002CEAC6 /* xicore.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = xicore.h; path = "../xi-modal-input/xicore.h"; sourceTree = "<group>"; };
40+
603608D2224EC693002CEAC6 /* xicore.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = xicore.h; path = "../xi-ffi/xicore.h"; sourceTree = "<group>"; };
4141
604B0F5F22405C88007038E6 /* XiCoreProxy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = XiCoreProxy.swift; sourceTree = "<group>"; };
4242
606644E7223FFED7006215A0 /* ModalInputTest.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = ModalInputTest.app; sourceTree = BUILT_PRODUCTS_DIR; };
4343
606644EA223FFED7006215A0 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
@@ -50,7 +50,7 @@
5050
606644FD223FFED9006215A0 /* ModalInputTestTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ModalInputTestTests.swift; sourceTree = "<group>"; };
5151
606644FF223FFED9006215A0 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
5252
609A225F22404CF900A3F007 /* libximodal.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libximodal.a; sourceTree = BUILT_PRODUCTS_DIR; };
53-
609A22662240504100A3F007 /* libximodal.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = libximodal.h; path = "../xi-modal-input/libximodal.h"; sourceTree = "<group>"; };
53+
609A22662240504100A3F007 /* libximodal.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = libximodal.h; path = "../xi-ffi/libximodal.h"; sourceTree = "<group>"; };
5454
609A2269224052B000A3F007 /* ModalInputTest-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "ModalInputTest-Bridging-Header.h"; sourceTree = "<group>"; };
5555
60BF2284225012DD002C0352 /* EditView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EditView.swift; sourceTree = "<group>"; };
5656
60CC174E224591840075FDE5 /* XiWindow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = XiWindow.swift; sourceTree = "<group>"; };
@@ -276,7 +276,7 @@
276276
);
277277
runOnlyForDeploymentPostprocessing = 0;
278278
shellPath = /bin/sh;
279-
shellScript = "# When building from Xcode we want to ensure that `cargo` is in PATH.\n# as a convenience, add the default cargo install location\nexport PATH=\"$PATH:${HOME}/.cargo/bin\"\n\nif [[ $CONFIGURATION = \"Debug\" ]]; then\n RUST_CONFIGURATION=\"debug\"\n RUST_CONFIGURATION_FLAG=\"\"\nelse\n RUST_CONFIGURATION=\"release\"\n RUST_CONFIGURATION_FLAG=\"--release\"\nfi\n\ncd \"${SRCROOT}/../xi-modal-input\"\n\necho \"rust config ${RUST_CONFIGURATION}\"\n\ncargo build $RUST_CONFIGURATION_FLAG\ncp \"${SRCROOT}/../xi-modal-input/target/${RUST_CONFIGURATION}/libximodal.a\" \"${SRCROOT}/\"\n";
279+
shellScript = "# When building from Xcode we want to ensure that `cargo` is in PATH.\n# as a convenience, add the default cargo install location\nexport PATH=\"$PATH:${HOME}/.cargo/bin\"\n\nset -e\n\nif [[ $CONFIGURATION = \"Debug\" ]]; then\n RUST_CONFIGURATION=\"debug\"\n RUST_CONFIGURATION_FLAG=\"\"\nelse\n RUST_CONFIGURATION=\"release\"\n RUST_CONFIGURATION_FLAG=\"--release\"\nfi\n\ncd \"${SRCROOT}/../xi-ffi\"\n\necho \"rust config ${RUST_CONFIGURATION}\"\nif [[ ${ACTION:-build} = \"build\" ]]; then\n cargo build $RUST_CONFIGURATION_FLAG\n cp \"${SRCROOT}/../xi-ffi/target/${RUST_CONFIGURATION}/libximodal.a\" \"${SRCROOT}/\"\nelif [[ $ACTION = \"clean\" ]]; then\n cargo clean\n rm \"${SRCROOT}/libximodal.a\"\nfi\n\nset +e\n";
280280
};
281281
609A226322404D0D00A3F007 /* ShellScript */ = {
282282
isa = PBXShellScriptBuildPhase;

xi-ffi/Cargo.toml

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
[package]
2+
name = "xi-ffi"
3+
version = "0.1.0"
4+
authors = ["Colin Rofls <[email protected]>"]
5+
edition = "2018"
6+
7+
[dependencies.xi-modal-input]
8+
path = "../xi-modal-input"
9+
version = "0.1"
10+
11+
[dependencies.libc]
12+
version = "0.2.17"
13+
default-features = false
14+
15+
[lib]
16+
name = "ximodal"
17+
path = "src/lib.rs"
18+
crate-type = ["staticlib"]
File renamed without changes.

xi-ffi/src/lib.rs

+154
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
use std::ffi::{CStr, CString};
2+
3+
use libc::{c_char, int32_t, uint32_t, size_t};
4+
extern crate xi_modal_input;
5+
use xi_modal_input::{XiCore, EventCtx, KeyEvent, EventPayload, Plumber, OneView, Vim};
6+
7+
#[repr(C)]
8+
pub struct XiLine {
9+
text: *const c_char,
10+
cursor: int32_t,
11+
selection: [int32_t; 2],
12+
}
13+
14+
#[no_mangle]
15+
pub extern "C" fn xiCoreCreate(
16+
rpc_callback: extern "C" fn(*const c_char),
17+
invalidate_callback: extern "C" fn(size_t, size_t),
18+
) -> *const XiCore {
19+
let r = Box::into_raw(Box::new(XiCore {
20+
rpc_callback,
21+
invalidate_callback,
22+
state: OneView::new(),
23+
plumber: None,
24+
handler: None,
25+
}));
26+
eprintln!("xiCore alloc {:?}", &r);
27+
r
28+
}
29+
30+
#[no_mangle]
31+
pub extern "C" fn xiCoreRegisterEventHandler(
32+
ptr: *mut XiCore,
33+
event_cb: extern "C" fn(*const EventPayload, bool),
34+
action_cb: extern "C" fn(*const c_char),
35+
timer_cb: extern "C" fn(*const EventPayload, uint32_t) -> uint32_t,
36+
cancel_timer_cb: extern "C" fn(uint32_t),
37+
) {
38+
let core = unsafe {
39+
assert!(!ptr.is_null(), "null pointer in xiCoreRegisterEventHandler");
40+
&mut *ptr
41+
};
42+
43+
let machine = Vim::new();
44+
let plumber = Plumber::new(event_cb, action_cb, timer_cb, cancel_timer_cb);
45+
core.plumber = Some(plumber);
46+
core.handler = Some(Box::new(machine));
47+
}
48+
49+
#[no_mangle]
50+
pub extern "C" fn xiCoreHandleInput(
51+
ptr: *mut XiCore,
52+
modifiers: uint32_t,
53+
characters: *const c_char,
54+
payload: *const EventPayload,
55+
) {
56+
let core = unsafe {
57+
assert!(!ptr.is_null());
58+
&mut *ptr
59+
};
60+
61+
let cstr = unsafe {
62+
assert!(!characters.is_null());
63+
CStr::from_ptr(characters)
64+
};
65+
66+
let characters = match cstr.to_str() {
67+
Ok(s) => s,
68+
Err(e) => {
69+
eprintln!("invalid cstr: {}, {:?}", e, cstr.to_bytes());
70+
""
71+
}
72+
};
73+
74+
let event = KeyEvent {
75+
characters,
76+
modifiers,
77+
payload,
78+
};
79+
80+
let ctx = EventCtx {
81+
plumber: core.plumber.as_ref().unwrap(),
82+
state: &mut core.state,
83+
};
84+
85+
let needs_render = core.handler.as_mut().unwrap().handle_event(event, ctx);
86+
if needs_render {
87+
core.send_update();
88+
}
89+
}
90+
91+
#[no_mangle]
92+
pub extern "C" fn xiCoreClearPending(ptr: *mut XiCore, token: uint32_t) {
93+
let core = unsafe {
94+
assert!(!ptr.is_null());
95+
&mut *ptr
96+
};
97+
98+
if core.handler.is_none() {
99+
eprintln!("unexpected None in xiCoreClearPending");
100+
}
101+
102+
core.handler.as_mut().map(|h| h.clear_pending(token));
103+
}
104+
105+
#[no_mangle]
106+
pub extern "C" fn xiCoreGetLine(ptr: *mut XiCore, idx: uint32_t) -> *const XiLine {
107+
let core = unsafe {
108+
assert!(!ptr.is_null(), "null pointer in xiCoreGetLine");
109+
&mut *ptr
110+
};
111+
112+
let (line, cursor, sel) = core.state.get_line(idx as usize).unwrap();
113+
let cstring = CString::new(line.as_ref()).expect("bad string, very sad");
114+
Box::into_raw(Box::new(XiLine {
115+
text: cstring.into_raw(),
116+
cursor,
117+
selection: [sel.0, sel.1],
118+
}))
119+
}
120+
121+
#[no_mangle]
122+
pub extern "C" fn xiCoreFree(ptr: *mut XiCore) {
123+
eprintln!("xiCore free {:?}", &ptr);
124+
if ptr.is_null() {
125+
return;
126+
}
127+
128+
unsafe {
129+
Box::from_raw(ptr);
130+
}
131+
}
132+
133+
#[no_mangle]
134+
pub extern "C" fn xiCoreSendMessage(ptr: *mut XiCore, msg: *const c_char) {
135+
let core = unsafe {
136+
assert!(!ptr.is_null(), "null pointer in xiCoreSendMessage");
137+
&mut *ptr
138+
};
139+
140+
let cstr = unsafe {
141+
assert!(!ptr.is_null(), "null msg pointer in xiCoreSendMessage");
142+
CStr::from_ptr(msg)
143+
};
144+
145+
let msg = match cstr.to_str() {
146+
Ok(s) => s,
147+
Err(e) => {
148+
eprintln!("invalid cstr: {}, {:?}", e, cstr.to_bytes());
149+
return;
150+
}
151+
};
152+
153+
core.handle_message(msg);
154+
}
File renamed without changes.

xi-modal-input/Cargo.toml

-4
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,3 @@ path = "/Users/rofls/dev/projects/xi-mac/xi-editor/rust/core-lib"
1717
[dependencies.xi-rope]
1818
path = "/Users/rofls/dev/projects/xi-mac/xi-editor/rust/rope"
1919

20-
[lib]
21-
name = "ximodal"
22-
path = "src/lib.rs"
23-
crate-type = ["staticlib"]

xi-modal-input/src/input_handler.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use libc::{c_char, uint32_t};
2-
use std::ffi::{CStr, CString};
2+
use std::ffi::CString;
33

44
use xi_core_lib::edit_types::EventDomain;
55

@@ -26,7 +26,7 @@ pub struct Plumber {
2626
}
2727

2828
impl Plumber {
29-
pub(crate) fn new(
29+
pub fn new(
3030
event_callback: extern "C" fn(*const EventPayload, bool),
3131
action_callback: extern "C" fn(*const c_char),
3232
timer_callback: extern "C" fn(*const EventPayload, uint32_t) -> uint32_t,

0 commit comments

Comments
 (0)