Skip to content

feat(candidate): allow arbitrary per-candidate data#1092

Open
ksqsf wants to merge 5 commits into
masterfrom
feat/cand-data
Open

feat(candidate): allow arbitrary per-candidate data#1092
ksqsf wants to merge 5 commits into
masterfrom
feat/cand-data

Conversation

@ksqsf

@ksqsf ksqsf commented Oct 7, 2025

Copy link
Copy Markdown
Member

允許給 Candidate 增加任意用字符串索引的數據。(此項變更僅面向插件,用戶無法直接使用。)

爲 Candidate 增加三個新的公開接口:

void set_data(const string& data_tag, an<void> datum);
an<void> get_data(const string& data_tag);
vector<string> get_data_keys();

插件可調用該接口,在產生 Candidate 時,附加任意數據。其中,datum 可設爲 null,則作用類似於 tags,但粒度是 Candidate。

一個可能的用例是:與 librime-lua 整合後,可以讓用戶編寫任意「Action Candidate」,這些 Candidate 不用來上屏文字,而是觸發任意邏輯。如:

  • 輸入 F ,得到候選「切換爲繁體」,選擇後不上屏任何內容,而是設置 simplification 爲 false
  • 輸入 J ,得到候選「切換爲簡體」,選擇後不上屏任何內容,而是設置 simplification 爲 true

接口本身還可以進一步討論。不過因爲這個接口只用於插件(考慮到插件已經和 librime 本體強綁定),日後要修改或許也不會有太大困難。

@ksqsf ksqsf requested review from a team and Copilot October 7, 2025 21:08

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull Request Overview

Adds a per-candidate data store so plugins can attach arbitrary data to Candidate instances, enabling action-style candidates and other plugin-driven behaviors.

  • Introduces set_data/get_data/get_data_keys public APIs on Candidate
  • Adds an internal map to hold arbitrary data keyed by strings

Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.

Comment thread src/rime/candidate.h Outdated
Comment thread src/rime/candidate.h Outdated
Comment thread src/rime/candidate.h Outdated
Comment thread src/rime/candidate.h
Comment thread src/rime/candidate.h
Comment on lines +44 to +58
// per-candidate data
void set_data(const string& data_tag, an<void> datum = nullptr) {
data_[data_tag] = datum;
}
an<void> get_data(const string& data_tag) {
auto it = data_.find(data_tag);
return it != data_.end() ? it->second : nullptr;
}
vector<string> get_data_keys() {
vector<string> keys;
for (const auto& pair : data_) {
keys.push_back(pair.first);
}
return keys;
}

Copilot AI Oct 7, 2025

Copy link

Choose a reason for hiding this comment

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

These new public APIs need clear documentation: ownership semantics of the stored pointers (who creates/destroys), expected type-erasure/casting pattern, whether nullptr is a supported value, thread-safety guarantees, and that get_data_keys returns keys in unspecified order. Please add brief doc comments for each method and the data_ member describing these behaviors.

Copilot uses AI. Check for mistakes.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Documentation is not a rime tradition ;-)

Comment thread src/rime/candidate.h
void set_quality(double quality) { quality_ = quality; }

// per-candidate data
void set_data(const string& data_tag, an<void> datum = nullptr) {

Copilot AI Oct 7, 2025

Copy link

Choose a reason for hiding this comment

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

[nitpick] Using void-erased pointers for arbitrary data is unsafe and forces consumers to manage casting/lifetimes. If feasible for the codebase standard, consider std::any (or an existing project-wide any/variant) for type-safe storage while still allowing arbitrary data.

Copilot uses AI. Check for mistakes.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

any is safer but is not naturally nullable, and optional<any> seems to have too many overheads.

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.

Null pointers sounds like absence of record / deletion, as you compared it to optional<any>.

ksqsf and others added 3 commits October 7, 2025 23:14
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
@ksqsf

ksqsf commented Oct 14, 2025

Copy link
Copy Markdown
Member Author

@lotem 来点反馈?

这个功能本身肯定是有必要的。比如说可以把 spelling hints 放到 data 里,这样就不需要占用 comment。

具体设计上可以再探讨。一个可能的简化法是改成 map<string, string>。

@lotem

lotem commented Oct 15, 2025

Copy link
Copy Markdown
Member

好的。

可否提供带模板参数的 get/set,因为用家总要做类型转换。

Comment thread src/rime/candidate.h
vector<string> keys;
keys.reserve(data_.size());
for (const auto& pair : data_) {
keys.push_back(pair.first);

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.

Check non-null?

Null pointers should be treated as absent.

Comment thread src/rime/candidate.h
void set_quality(double quality) { quality_ = quality; }

// per-candidate data
void set_data(const string& data_tag, an<void> datum = nullptr) {

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.

Null pointers sounds like absence of record / deletion, as you compared it to optional<any>.

Comment thread src/rime/candidate.h
}
an<void> get_data(const string& data_tag) const {
auto it = data_.find(data_tag);
return it != data_.end() ? it->second : nullptr;

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.

Another proof: null pointer and absence are equal.

@ksqsf

ksqsf commented Jan 5, 2026

Copy link
Copy Markdown
Member Author

之后改一下。目前有个想法是,大部分用例应该都是 string 类型(candidate 级的 tag),所以应该用类似 variant<string, shared_ptr> 的结构来减少 shared_ptr 引入的开销。

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.

3 participants