Skip to content

Commit 025d9fb

Browse files
committed
fix(chord_composer): more safely handle the placeholder ZWSP
sometimes Rime outputs an invalid character, invisible among text or being visualized as diamond with question mark in macOS. I observed this bug often when I was using combo pinyin but still not sure if this code has to do with the issue. just mark the placeholder segment "phony" to prevent accidentally commiting the ZWSP character.
1 parent bb94093 commit 025d9fb

File tree

1 file changed

+22
-23
lines changed

1 file changed

+22
-23
lines changed

src/rime/gear/chord_composer.cc

+22-23
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,7 @@
1313
#include <rime/schema.h>
1414
#include <rime/gear/chord_composer.h>
1515

16-
// U+FEFF works better with MacType
17-
static const char* kZeroWidthSpace = "\xef\xbb\xbf"; //"\xe2\x80\x8b";
16+
static const char* kZeroWidthSpace = "\xe2\x80\x8b"; // U+200B
1817

1918
namespace rime {
2019

@@ -118,8 +117,9 @@ ProcessResult ChordComposer::ProcessChordingKey(const KeyEvent& key_event) {
118117
return kAccepted;
119118
}
120119

121-
inline static bool is_composing_text(Context* ctx) {
122-
return ctx->IsComposing() && ctx->input() != kZeroWidthSpace;
120+
inline static bool is_composing(Context* ctx) {
121+
return !ctx->composition().empty() &&
122+
!ctx->composition().back().HasTag("phony");
123123
}
124124

125125
ProcessResult ChordComposer::ProcessKeyEvent(const KeyEvent& key_event) {
@@ -133,7 +133,7 @@ ProcessResult ChordComposer::ProcessKeyEvent(const KeyEvent& key_event) {
133133
int ch = key_event.keycode();
134134
if (!is_key_up && ch >= 0x20 && ch <= 0x7e) {
135135
// save raw input
136-
if (!is_composing_text(engine_->context()) || !raw_sequence_.empty()) {
136+
if (!is_composing(engine_->context()) || !raw_sequence_.empty()) {
137137
raw_sequence_.push_back(ch);
138138
DLOG(INFO) << "update raw sequence: " << raw_sequence_;
139139
}
@@ -164,18 +164,17 @@ void ChordComposer::UpdateChord() {
164164
string code = SerializeChord();
165165
prompt_format_.Apply(&code);
166166
if (comp.empty()) {
167-
// add an invisbile place holder segment
167+
// add a placeholder segment
168168
// 1. to cheat ctx->IsComposing() == true
169169
// 2. to attach chord prompt to while chording
170-
ctx->PushInput(kZeroWidthSpace);
171-
if (comp.empty()) {
172-
LOG(ERROR) << "failed to update chord.";
173-
return;
174-
}
175-
comp.back().tags.insert("phony");
176-
}
177-
comp.back().tags.insert("chord_prompt");
178-
comp.back().prompt = code;
170+
ctx->set_input(kZeroWidthSpace);
171+
Segment placeholder(0, ctx->input().length());
172+
placeholder.tags.insert("phony");
173+
ctx->composition().AddSegment(placeholder);
174+
}
175+
auto& last_segment = comp.back();
176+
last_segment.tags.insert("chord_prompt");
177+
last_segment.prompt = code;
179178
}
180179

181180
void ChordComposer::FinishChord() {
@@ -207,20 +206,20 @@ void ChordComposer::ClearChord() {
207206
return;
208207
Context* ctx = engine_->context();
209208
Composition& comp = ctx->composition();
210-
if (comp.empty()) {
209+
if (comp.empty())
211210
return;
211+
auto& last_segment = comp.back();
212+
if (comp.size() == 1 && last_segment.HasTag("phony")) {
213+
ctx->Clear();
212214
}
213-
if (comp.input().substr(comp.back().start) == kZeroWidthSpace) {
214-
ctx->PopInput(ctx->caret_pos() - comp.back().start);
215-
}
216-
else if (comp.back().HasTag("chord_prompt")) {
217-
comp.back().prompt.clear();
218-
comp.back().tags.erase("chord_prompt");
215+
else if (last_segment.HasTag("chord_prompt")) {
216+
last_segment.prompt.clear();
217+
last_segment.tags.erase("chord_prompt");
219218
}
220219
}
221220

222221
void ChordComposer::OnContextUpdate(Context* ctx) {
223-
if (is_composing_text(ctx)) {
222+
if (is_composing(ctx)) {
224223
composing_ = true;
225224
}
226225
else if (composing_) {

0 commit comments

Comments
 (0)