Skip to content

Commit d88ef9f

Browse files
committed
feat(tools/rime_proto_console): demo for proto api
1 parent aae7a0c commit d88ef9f

File tree

3 files changed

+255
-9
lines changed

3 files changed

+255
-9
lines changed

tools/CMakeLists.txt

+22-9
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,32 @@
11
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)
22

3-
set(rime_api_console_src "rime_api_console.cc")
4-
add_executable(rime_api_console ${rime_api_console_src})
5-
target_link_libraries(rime_api_console
3+
set(rime_console_deps
64
${rime_library}
75
${rime_dict_library}
86
${rime_gears_library}
97
${rime_levers_library}
108
${rime_plugins_library})
119

10+
set(rime_api_console_src "rime_api_console.cc")
11+
add_executable(rime_api_console ${rime_api_console_src})
12+
target_link_libraries(rime_api_console ${rime_console_deps})
13+
14+
set(CAPNPC_IMPORT_DIRS ${CAPNPC_IMPORT_DIRS} ${RIME_PROTO_SCHEMA_DIR})
15+
capnp_generate_cpp(CAPNP_SRCS CAPNP_HDRS rime_message.capnp)
16+
message(STATUS "compiled capnproto schemata (sources): ${CAPNP_SRCS}")
17+
message(STATUS "compiled capnproto schemata (headers): ${CAPNP_HDRS}")
18+
19+
set(rime_proto_console_src
20+
"rime_proto_console.cc"
21+
${CAPNP_SRCS}
22+
${rime_proto_objs})
23+
add_executable(rime_proto_console ${rime_proto_console_src})
24+
target_link_libraries(rime_proto_console ${rime_console_deps})
25+
target_include_directories(rime_proto_console
26+
PRIVATE
27+
${CMAKE_CURRENT_BINARY_DIR}
28+
${RIME_PROTO_INCLUDE_DIR})
29+
1230
set(rime_patch_src "rime_patch.cc")
1331
add_executable(rime_patch ${rime_patch_src})
1432
target_link_libraries(rime_patch
@@ -20,12 +38,7 @@ if(NOT (WIN32 AND BUILD_SHARED_LIBS))
2038

2139
set(rime_console_src "rime_console.cc")
2240
add_executable(rime_console ${rime_console_src})
23-
target_link_libraries(rime_console
24-
${rime_library}
25-
${rime_dict_library}
26-
${rime_gears_library}
27-
${rime_levers_library}
28-
${rime_plugins_library})
41+
target_link_libraries(rime_console ${rime_console_deps})
2942

3043
set(rime_dict_manager_src "rime_dict_manager.cc")
3144
add_executable(rime_dict_manager ${rime_dict_manager_src})

tools/rime_message.capnp

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
@0xd30600b3651feef7;
2+
3+
using Rime = import "/rime_proto.capnp";
4+
5+
struct RimeMessage {
6+
commit @0 :Rime.Commit;
7+
context @1 :Rime.Context;
8+
status @2 :Rime.Status;
9+
}

tools/rime_proto_console.cc

+224
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,224 @@
1+
/*
2+
* Copyright RIME Developers
3+
* Distributed under the BSD License
4+
*
5+
* 2011-08-29 GONG Chen <chen.sst@gmail.com>
6+
*/
7+
#include <algorithm>
8+
#include <iostream>
9+
#include <string>
10+
#include <capnp/message.h>
11+
#include <rime_api.h>
12+
#include <rime_message.capnp.h>
13+
#include <rime_proto.capnp.h>
14+
15+
void print_status(rime::proto::Status::Reader status) {
16+
std::cout << "schema: " << status.getSchemaId().cStr()
17+
<< " / " << status.getSchemaName().cStr() << std::endl;
18+
std::cout << "status:";
19+
if (status.getIsDisabled()) std::cout << " disabled";
20+
if (status.getIsComposing()) std::cout << " composing";
21+
if (status.getIsAsciiMode()) std::cout << " ascii";
22+
if (status.getIsFullShape()) std::cout << " full_shape";
23+
if (status.getIsSimplified()) std::cout << " simplified";
24+
std::cout << std::endl;
25+
}
26+
27+
void print_composition(rime::proto::Context::Composition::Reader composition) {
28+
if (!composition.hasPreedit()) return;
29+
std::string preedit = composition.getPreedit();
30+
size_t len = composition.getLength();
31+
size_t start = composition.getSelStart();
32+
size_t end = composition.getSelEnd();
33+
size_t cursor = composition.getCursorPos();
34+
for (size_t i = 0; i <= len; ++i) {
35+
if (start < end) {
36+
if (i == start) {
37+
std::cout << '[';
38+
} else if (i == end) {
39+
std::cout << ']';
40+
}
41+
}
42+
if (i == cursor) std::cout << '|';
43+
if (i < len)
44+
std::cout << preedit[i];
45+
}
46+
std::cout << std::endl;
47+
}
48+
49+
void print_menu(rime::proto::Context::Menu::Reader menu) {
50+
int num_candidates = menu.getCandidates().size();
51+
if (num_candidates == 0) return;
52+
std::cout << "page: " << (menu.getPageNumber() + 1)
53+
<< (menu.getIsLastPage() ? '$' : ' ')
54+
<< " (of size " << menu.getPageSize() << ")" << std::endl;
55+
for (int i = 0; i < num_candidates; ++i) {
56+
bool highlighted = i == menu.getHighlightedCandidateIndex();
57+
auto candidate = menu.getCandidates()[i];
58+
std::cout << (i + 1) << ". "
59+
<< (highlighted ? '[' : ' ')
60+
<< candidate.getText().cStr()
61+
<< (highlighted ? ']' : ' ');
62+
if (candidate.hasComment())
63+
std::cout << candidate.getComment().cStr();
64+
std::cout << std::endl;
65+
}
66+
}
67+
68+
void print_context(rime::proto::Context::Reader context) {
69+
auto composition = context.getComposition();
70+
if (composition.getLength() > 0) {
71+
print_composition(composition);
72+
print_menu(context.getMenu());
73+
} else {
74+
std::cout << "(not composing)" << std::endl;
75+
}
76+
}
77+
78+
void print(RimeSessionId session_id) {
79+
RimeApi* rime = rime_get_api();
80+
81+
::capnp::MallocMessageBuilder message_builder;
82+
RimeMessage::Builder root = message_builder.initRoot<RimeMessage>();
83+
84+
auto commit_builder = root.getCommit();
85+
rime->commit_proto(session_id, &commit_builder);
86+
auto commit_reader = commit_builder.asReader();
87+
if (commit_reader.hasText()) {
88+
std::cout << "commit: " << commit_reader.getText().cStr() << std::endl;
89+
}
90+
91+
auto status_builder = root.getStatus();
92+
rime->status_proto(session_id, &status_builder);
93+
print_status(status_builder.asReader());
94+
95+
auto context_builder = root.getContext();
96+
rime->context_proto(session_id, &context_builder);
97+
print_context(context_builder.asReader());
98+
}
99+
100+
inline static bool is_prefix_of(const std::string& str,
101+
const std::string& prefix) {
102+
return std::mismatch(prefix.begin(),
103+
prefix.end(),
104+
str.begin()).first == prefix.end();
105+
}
106+
107+
bool execute_special_command(const std::string& line,
108+
RimeSessionId session_id) {
109+
RimeApi* rime = rime_get_api();
110+
if (line == "print schema list") {
111+
RimeSchemaList list;
112+
if (rime->get_schema_list(&list)) {
113+
std::cout << "schema list:" << std::endl;
114+
for (size_t i = 0; i < list.size; ++i) {
115+
std::cout << (i + 1) << ". " << list.list[i].name
116+
<< " [" << list.list[i].schema_id << "]" << std::endl;
117+
}
118+
rime->free_schema_list(&list);
119+
}
120+
char current[100] = {0};
121+
if (rime->get_current_schema(session_id, current, sizeof(current))) {
122+
std::cout << "current schema: [" << current << "]" << std::endl;
123+
}
124+
return true;
125+
}
126+
const std::string kSelectSchema = "select schema ";
127+
if (is_prefix_of(line, kSelectSchema)) {
128+
auto schema_id = line.substr(kSelectSchema.length());
129+
if (rime->select_schema(session_id, schema_id.c_str())) {
130+
std::cout << "selected schema: [" << schema_id << "]" << std::endl;
131+
}
132+
return true;
133+
}
134+
const std::string kSelectCandidate = "select candidate ";
135+
if (is_prefix_of(line, kSelectCandidate)) {
136+
int index = std::stoi(line.substr(kSelectCandidate.length()));
137+
if (index > 0 &&
138+
rime->select_candidate_on_current_page(session_id, index - 1)) {
139+
print(session_id);
140+
} else {
141+
std::cerr << "cannot select candidate at index " << index << "."
142+
<< std::endl;
143+
}
144+
return true;
145+
}
146+
if (line == "print candidate list") {
147+
RimeCandidateListIterator iterator = {0};
148+
if (rime->candidate_list_begin(session_id, &iterator)) {
149+
while (rime->candidate_list_next(&iterator)) {
150+
std::cout << (iterator.index + 1) << ". " << iterator.candidate.text;
151+
if (iterator.candidate.comment)
152+
std::cout << " (" << iterator.candidate.comment << ")";
153+
std::cout << std::endl;
154+
}
155+
rime->candidate_list_end(&iterator);
156+
} else {
157+
std::cout << "no candidates." << std::endl;
158+
}
159+
return true;
160+
}
161+
const std::string kSetOption = "set option ";
162+
if (is_prefix_of(line, kSetOption)) {
163+
Bool is_on = True;
164+
auto iter = line.begin() + kSetOption.length();
165+
const auto end = line.end();
166+
if (iter != end && *iter == '!') {
167+
is_on = False;
168+
++iter;
169+
}
170+
auto option = std::string(iter, end);
171+
rime->set_option(session_id, option.c_str(), is_on);
172+
std::cout << option << " set " << (is_on ? "on" : "off") << std::endl;
173+
return true;
174+
}
175+
return false;
176+
}
177+
178+
void on_message(void* context_object,
179+
RimeSessionId session_id,
180+
const char* message_type,
181+
const char* message_value) {
182+
std::cout << "message: [" << session_id << "] [" << message_type << "] "
183+
<< message_value << std::endl;
184+
}
185+
186+
int main(int argc, char *argv[]) {
187+
RimeApi* rime = rime_get_api();
188+
189+
RIME_STRUCT(RimeTraits, traits);
190+
traits.app_name = "rime.console";
191+
rime->setup(&traits);
192+
193+
rime->set_notification_handler(&on_message, NULL);
194+
195+
std::cerr << "initializing..." << std::endl;
196+
rime->initialize(NULL);
197+
Bool full_check = True;
198+
if (rime->start_maintenance(full_check))
199+
rime->join_maintenance_thread();
200+
std::cerr << "ready." << std::endl;
201+
202+
RimeSessionId session_id = rime->create_session();
203+
if (!session_id) {
204+
std::cerr << "Error creating rime session." << std::endl;
205+
return 1;
206+
}
207+
208+
std::string line;
209+
while (std::getline(std::cin, line)) {
210+
if (line == "exit")
211+
break;
212+
if (execute_special_command(line, session_id))
213+
continue;
214+
if (rime->simulate_key_sequence(session_id, line.c_str())) {
215+
print(session_id);
216+
} else {
217+
std::cerr << "Error processing key sequence: " << line << std::endl;
218+
}
219+
}
220+
221+
rime->destroy_session(session_id);
222+
rime->finalize();
223+
return 0;
224+
}

0 commit comments

Comments
 (0)