Skip to content

feat(api): add RimeCandidatePreview for inline preedit - #1208

Merged
lotem merged 2 commits into
rime:masterfrom
ecstasoy:feat/candidate-preview-api
Aug 10, 2026
Merged

feat(api): add RimeCandidatePreview for inline preedit#1208
lotem merged 2 commits into
rime:masterfrom
ecstasoy:feat/candidate-preview-api

Conversation

@ecstasoy

@ecstasoy ecstasoy commented Aug 8, 2026

Copy link
Copy Markdown
Contributor

Pull request

Issue tracker

Fixes will automatically close the related issue

Fixes #1163

Feature

The alignment between the raw preedit input and the candidate text is only known accurately inside librime; a frontend cannot reliably reconstruct it from the outside. That reconstruction is the root cause of a recurring class of crashes — rime/squirrel#1041 / rime/squirrel#1045 / rime/squirrel#1047 / rime/squirrel#1081 — where the preedit offsets (e.g. pinyin) and the Han-character commit_text_preview don't line up.

This exposes a new CandidatePreview API that returns the text a candidate would commit, already split at the selection boundary into three parts:

typedef struct {
  int data_size;
  char* text_before_selection;
  char* selected_text;
  char* text_after_selection;
  Bool has_remaining_input;
} RimeCandidatePreview;

Bool (*get_candidate_preview)(RimeSessionId, size_t index, RimeCandidatePreview*);
Bool (*get_candidate_preview_on_current_page)(RimeSessionId, size_t index, RimeCandidatePreview*);
Bool (*free_candidate_preview)(RimeCandidatePreview*);

Unit test

  • Done

Manual test

  • Done

Code Review

  1. Unit and manual test pass
  2. GitHub Action CI pass
  3. At least one contributor reviews and votes
  4. Can be merged clean without conflicts
  5. PR will be merged by rebase upstream base

Additional Info

The Old Approach
After:

if inlineCandidate {
  var preview = RimeCandidatePreview.rimeStructInit()
  _ = rimeAPI.get_candidate_preview(session, &preview)
  let before = preview.text_before_selection.map { String(cString: $0) } ?? ""
  let selected = preview.selected_text.map { String(cString: $0) } ?? ""
  let after = preview.text_after_selection.map { String(cString: $0) } ?? ""
  let hasRemaining = preview.text_after_selection != nil
  _ = rimeAPI.free_candidate_preview(&preview)

  let display = (inlinePreedit || !hasRemaining) ? before + selected + after : before + selected
  let selLocation = before.utf16.count
  show(preedit: display,
       selRange: NSRange(location: selLocation, length: selected.utf16.count),
       caretPos: selLocation + selected.utf16.count)
}

已在本地自行编译并将使用新API的鼠须管作为日常输入法使用过一段时间,测试过不同方案(魔然/雾凇/默认),上述issue均不再复现,也没有发现其他问题。

Comment thread src/rime/context.h Outdated
Comment thread src/rime/composition.h Outdated
Comment thread src/rime_api_impl.h
Comment thread src/rime_api_impl.h Outdated
@ecstasoy
ecstasoy force-pushed the feat/candidate-preview-api branch from df185e2 to d7ba373 Compare August 9, 2026 08:03

@lotem lotem left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, please take another look.

Comment thread src/rime_api.h Outdated

Bool (*change_page)(RimeSessionId session_id, Bool backward);

//! get the candidate preview at an absolute candidate index

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Update the comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

updated

Comment thread src/rime_api_impl.h
@ecstasoy
ecstasoy force-pushed the feat/candidate-preview-api branch from d7ba373 to 8cc1964 Compare August 9, 2026 12:36

@lotem lotem left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, LGTM

@lotem
lotem merged commit 4901c8a into rime:master Aug 10, 2026
10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

新增一个 CandidatePreview 接口,简化前端的边界问题处理

2 participants