Skip to content

Commit 90d8585

Browse files
committed
cskk v3.0 with completion
1 parent ebf937a commit 90d8585

7 files changed

+98
-21
lines changed

CMakeLists.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ find_package(Fcitx5Core 5.0.6 REQUIRED)
2222
find_package(Fcitx5Utils 5.0.6 REQUIRED)
2323

2424
# GITHUB_ACTION_BUILD_CSKK_VERSION=2.0.0
25-
pkg_check_modules(LIBCSKK REQUIRED IMPORTED_TARGET "cskk>=2.0")
25+
pkg_check_modules(LIBCSKK REQUIRED IMPORTED_TARGET "cskk>=3.0")
2626

2727
option(ENABLE_QT "Enable Qt for GUI configuration" On)
2828

development.org

+4
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,10 @@ Should update these files and then create a deploy on github
3131
Following semver rule but with tweak same as rust lang's cargo.
3232
Initial development releases starting with "0.y.z" can treat changes in "y" as a major release, and "z" as a minor release.
3333

34+
** Shared lib places
35+
Fcitx5 finds addon from FCITX_ADDON_DIRS env var, a colon (':') separated dir list. fallbacks to FCITX_INSTALL_ADDONDIR configured on build.
36+
e.g. FCITX_ADDON_DIRS=build/src:/usr/lib/x86_64-linux-gnu/fcitx5 fcitx5 --verbose=*=5
37+
3438
* Q
3539
** How config works?
3640
Create Option class.

gui/adddictdialog.cpp

+10
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ AddDictDialog::AddDictDialog(QWidget *parent)
3232
m_ui->typeComboBox->addItem(_("System"));
3333
m_ui->typeComboBox->addItem(_("User"));
3434
m_ui->typeComboBox->setCurrentIndex(1);
35+
// m_ui->completeNoRadio
3536

3637
indexChanged();
3738

@@ -57,6 +58,11 @@ QMap<QString, QString> AddDictDialog::dictionary() {
5758
dict["file"] = m_ui->urlLineEdit->text();
5859
dict["mode"] = mode_type[idx];
5960
dict["encoding"] = m_ui->encodingEdit->text();
61+
if (m_ui->completeYesRadio->isChecked()) {
62+
dict["complete"] = "true";
63+
} else {
64+
dict["complete"] = "false";
65+
}
6066

6167
return dict;
6268
}
@@ -120,6 +126,7 @@ void AddDictDialog::browseClicked() {
120126
}
121127
validate();
122128
}
129+
123130
void AddDictDialog::setDictionary(QMap<QString, QString> &dict) {
124131
m_ui->urlLineEdit->setText(dict["file"]);
125132

@@ -130,6 +137,9 @@ void AddDictDialog::setDictionary(QMap<QString, QString> &dict) {
130137
}
131138
}
132139
m_ui->encodingEdit->setText(dict["encoding"]);
140+
if (dict["complete"] == "complete") {
141+
m_ui->completeYesRadio->setChecked(true);
142+
}
133143
}
134144

135145
} // namespace fcitx

gui/adddictdialog.ui

+28-13
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@
66
<rect>
77
<x>0</x>
88
<y>0</y>
9-
<width>361</width>
10-
<height>153</height>
9+
<width>507</width>
10+
<height>202</height>
1111
</rect>
1212
</property>
1313
<property name="windowTitle">
@@ -84,18 +84,33 @@
8484
</property>
8585
</widget>
8686
</item>
87-
<item row="3" column="1">
88-
<spacer name="verticalSpacer">
89-
<property name="orientation">
90-
<enum>Qt::Vertical</enum>
91-
</property>
92-
<property name="sizeHint" stdset="0">
93-
<size>
94-
<width>20</width>
95-
<height>40</height>
96-
</size>
87+
<item row="3" column="0">
88+
<widget class="QLabel" name="completeLabel">
89+
<property name="text">
90+
<string>TextLabel</string>
9791
</property>
98-
</spacer>
92+
</widget>
93+
</item>
94+
<item row="3" column="1">
95+
<layout class="QHBoxLayout" name="horizontalLayout_5">
96+
<item>
97+
<widget class="QRadioButton" name="completeNoRadio">
98+
<property name="text">
99+
<string>Do not complete</string>
100+
</property>
101+
<property name="checked">
102+
<bool>true</bool>
103+
</property>
104+
</widget>
105+
</item>
106+
<item>
107+
<widget class="QRadioButton" name="completeYesRadio">
108+
<property name="text">
109+
<string>Use for complete</string>
110+
</property>
111+
</widget>
112+
</item>
113+
</layout>
99114
</item>
100115
</layout>
101116
</item>

gui/dictmodel.cpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/*
2-
* SPDX-FileCopyrightText: <text>2013~2022 CSSlayer <[email protected]>, Naoaki Iwakiri
3-
* <[email protected]></text>
2+
* SPDX-FileCopyrightText: <text>2013~2022 CSSlayer <[email protected]>, Naoaki
3+
* Iwakiri <[email protected]></text>
44
*
55
* SPDX-License-Identifier: GPL-3.0-or-later
66
*

gui/dictmodel.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ class SkkDictModel : public QAbstractListModel {
3838
static QMap<QString, QString> parseLine(const QString &line);
3939
static QString serialize(const QMap<QString, QString> &dict);
4040
inline static QSet<QString> m_knownKeys =
41-
QSet<QString>({"file", "type", "mode", "encoding"});
41+
QSet<QString>({"file", "type", "mode", "encoding", "complete"});
4242

4343
private:
4444
QList<QMap<QString, QString>> m_dicts;

src/cskk.cpp

+52-4
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include <filesystem>
2323
#include <string>
2424
#include <vector>
25+
2526
extern "C" {
2627
#include <fcntl.h>
2728
}
@@ -46,7 +47,9 @@ FcitxCskkEngine::FcitxCskkEngine(Instance *instance)
4647
reloadConfig();
4748
instance_->inputContextManager().registerProperty("cskkcontext", &factory_);
4849
}
50+
4951
FcitxCskkEngine::~FcitxCskkEngine() = default;
52+
5053
void FcitxCskkEngine::keyEvent(const InputMethodEntry &, KeyEvent &keyEvent) {
5154
CSKK_DEBUG() << "Engine keyEvent start: " << keyEvent.rawKey();
5255
// delegate to context
@@ -55,6 +58,7 @@ void FcitxCskkEngine::keyEvent(const InputMethodEntry &, KeyEvent &keyEvent) {
5558
context->keyEvent(keyEvent);
5659
CSKK_DEBUG() << "Engine keyEvent end";
5760
}
61+
5862
void FcitxCskkEngine::save() {
5963
if (factory_.registered()) {
6064
instance_->inputContextManager().foreach ([this](InputContext *ic) {
@@ -63,24 +67,29 @@ void FcitxCskkEngine::save() {
6367
});
6468
}
6569
}
70+
6671
void FcitxCskkEngine::activate(const InputMethodEntry &, InputContextEvent &) {}
72+
6773
void FcitxCskkEngine::deactivate(const InputMethodEntry &entry,
6874
InputContextEvent &event) {
6975
reset(entry, event);
7076
}
77+
7178
void FcitxCskkEngine::reset(const InputMethodEntry &,
7279
InputContextEvent &event) {
7380
CSKK_DEBUG() << "Reset";
7481
auto ic = event.inputContext();
7582
auto context = ic->propertyFor(&factory_);
7683
context->reset();
7784
}
85+
7886
void FcitxCskkEngine::setConfig(const RawConfig &config) {
7987
CSKK_DEBUG() << "Cskk setconfig";
8088
config_.load(config, true);
8189
safeSaveAsIni(config_, FcitxCskkEngine::config_file_path);
8290
reloadConfig();
8391
}
92+
8493
void FcitxCskkEngine::reloadConfig() {
8594
CSKK_DEBUG() << "Cskkengine reload config";
8695
readAsIni(config_, FcitxCskkEngine::config_file_path);
@@ -96,6 +105,7 @@ void FcitxCskkEngine::reloadConfig() {
96105
}
97106

98107
typedef enum _FcitxSkkDictType { FSDT_Invalid, FSDT_File } FcitxSkkDictType;
108+
99109
void FcitxCskkEngine::loadDictionary() {
100110
freeDictionaries();
101111

@@ -124,6 +134,8 @@ void FcitxCskkEngine::loadDictionary() {
124134
int mode = 0;
125135
std::string path;
126136
std::string encoding;
137+
bool complete = false;
138+
127139
for (auto &token : tokens) {
128140
auto equal = token.find('=');
129141
if (equal == std::string::npos) {
@@ -149,6 +161,10 @@ void FcitxCskkEngine::loadDictionary() {
149161
}
150162
} else if (key == "encoding") {
151163
encoding = value;
164+
} else if (key == "complete") {
165+
if (value == "true") {
166+
complete = true;
167+
}
152168
}
153169
}
154170

@@ -165,9 +181,11 @@ void FcitxCskkEngine::loadDictionary() {
165181
}
166182
if (mode == 1) {
167183
// readonly mode
168-
auto *dict = skk_file_dict_new(path.c_str(), encoding.c_str());
184+
auto *dict =
185+
skk_file_dict_new(path.c_str(), encoding.c_str(), complete);
169186
if (dict) {
170-
CSKK_DEBUG() << "Adding file dict: " << path;
187+
CSKK_DEBUG() << "Adding file dict: " << path
188+
<< " complete:" << complete;
171189
dictionaries_.emplace_back(dict);
172190
} else {
173191
CSKK_WARN() << "Static dictionary load error. Ignored: " << path;
@@ -182,7 +200,8 @@ void FcitxCskkEngine::loadDictionary() {
182200
StandardPath::global().userDirectory(StandardPath::Type::PkgData),
183201
path.substr(var_len));
184202
}
185-
auto *userdict = skk_user_dict_new(realpath.c_str(), encoding.c_str());
203+
auto *userdict =
204+
skk_user_dict_new(realpath.c_str(), encoding.c_str(), complete);
186205
if (userdict) {
187206
CSKK_DEBUG() << "Adding user dict: " << realpath;
188207
dictionaries_.emplace_back(userdict);
@@ -201,6 +220,7 @@ void FcitxCskkEngine::freeDictionaries() {
201220
}
202221
dictionaries_.clear();
203222
}
223+
204224
KeyList FcitxCskkEngine::getSelectionKeys(
205225
CandidateSelectionKeys candidateSelectionKeys) {
206226
switch (candidateSelectionKeys) {
@@ -223,6 +243,7 @@ KeyList FcitxCskkEngine::getSelectionKeys(
223243
Key(FcitxKey_0)};
224244
}
225245
}
246+
226247
std::string FcitxCskkEngine::subModeIconImpl(const InputMethodEntry &,
227248
InputContext &ic) {
228249
auto context = ic.propertyFor(&factory_);
@@ -242,6 +263,7 @@ std::string FcitxCskkEngine::subModeIconImpl(const InputMethodEntry &,
242263
return "";
243264
}
244265
}
266+
245267
bool FcitxCskkEngine::isEngineReady() { return factory_.registered(); }
246268

247269
/*******************************************************************************
@@ -256,7 +278,9 @@ FcitxCskkContext::FcitxCskkContext(FcitxCskkEngine *engine, InputContext *ic)
256278
CSKK_ERROR() << "Failed to create new cskk context";
257279
}
258280
}
281+
259282
FcitxCskkContext::~FcitxCskkContext() { skk_free_context(context_); }
283+
260284
void FcitxCskkContext::keyEvent(KeyEvent &keyEvent) {
261285
if (!context_) {
262286
CSKK_ERROR() << "CSKK Context is not setup. Ignored key.";
@@ -291,6 +315,7 @@ void FcitxCskkContext::keyEvent(KeyEvent &keyEvent) {
291315
updateUI();
292316
}
293317
}
318+
294319
bool FcitxCskkContext::handleCandidateSelection(
295320
const std::shared_ptr<FcitxCskkCandidateList> &candidateList,
296321
KeyEvent &keyEvent) {
@@ -331,9 +356,12 @@ bool FcitxCskkContext::handleCandidateSelection(
331356
}
332357

333358
void FcitxCskkContext::reset() {
334-
skk_context_reset(context_);
359+
if (context_) {
360+
skk_context_reset(context_);
361+
}
335362
updateUI();
336363
}
364+
337365
void FcitxCskkContext::updateUI() {
338366
if (!context_) {
339367
CSKK_WARN() << "No context setup";
@@ -403,6 +431,7 @@ void FcitxCskkContext::updateUI() {
403431
ic_->updateUserInterface(UserInterfaceComponent::StatusArea);
404432
ic_->updateUserInterface(UserInterfaceComponent::InputPanel);
405433
}
434+
406435
void FcitxCskkContext::applyConfig() {
407436
CSKK_DEBUG() << "apply config";
408437
if (!context_) {
@@ -418,6 +447,7 @@ void FcitxCskkContext::applyConfig() {
418447
skk_context_set_period_style(context_, *config.periodStyle);
419448
skk_context_set_comma_style(context_, *config.commaStyle);
420449
}
450+
421451
void FcitxCskkContext::copyTo(InputContextProperty *) {
422452
// auto otherContext = dynamic_cast<FcitxCskkContext *>(context);
423453
// Ignored.
@@ -426,6 +456,7 @@ void FcitxCskkContext::copyTo(InputContextProperty *) {
426456
// fcitx5-cskk will just hold each cskkcontext in each input context's
427457
// property and shares nothing.
428458
}
459+
429460
bool FcitxCskkContext::saveDictionary() {
430461
if (!context_) {
431462
CSKK_WARN() << "No cskk context setup. Ignored dictionary save.";
@@ -435,13 +466,15 @@ bool FcitxCskkContext::saveDictionary() {
435466
// cskk v0.8 doesn't return value on save dict, return true for now.
436467
return true;
437468
}
469+
438470
int FcitxCskkContext::getInputMode() {
439471
if (!context_) {
440472
CSKK_WARN() << "No cskk context setup. No inputmode.";
441473
return -1;
442474
}
443475
return skk_context_get_input_mode(context_);
444476
}
477+
445478
/**
446479
* format preedit state into Text.
447480
* Returns tuple of <Main content Text, Supplement content Text>
@@ -453,6 +486,7 @@ FcitxCskkContext::formatPreedit(CskkStateInfoFfi *cskkStateInfoArray,
453486
uint32_t stateLen) {
454487
std::string precomposition_marker = "";
455488
std::string selection_marker = "";
489+
std::string completion_marker = "";
456490
Text mainContent = Text(""), supplementContent = Text("");
457491
mainContent.clear();
458492
supplementContent.clear();
@@ -564,11 +598,25 @@ FcitxCskkContext::formatPreedit(CskkStateInfoFfi *cskkStateInfoArray,
564598
mainCursorIdx += strlen("");
565599
mainContent.append("", TextFormatFlag::DontCommit);
566600
} break;
601+
case CompleteStateInfo: {
602+
auto completeStateInfo = cskkStateInfo.complete_state_info;
603+
mainContent.append(completion_marker, TextFormatFlag::DontCommit);
604+
if (completeStateInfo.completed) {
605+
mainCursorIdx += strlen(completeStateInfo.completed);
606+
mainContent.append(completeStateInfo.completed,
607+
TextFormatFlag::Underline);
608+
}
609+
if (completeStateInfo.completed_midashi) {
610+
supplementContent.append(completeStateInfo.completed_midashi,
611+
TextFormatFlag::DontCommit);
612+
}
613+
} break;
567614
}
568615
}
569616
// FIXME: Silently assuming length is less than int_max here. May fail when
570617
// length is over UINT_MAX. very unlikely, not high priority.
571618
mainContent.setCursor((int)mainCursorIdx);
619+
// Starting from 1 on purpose. No paren for submodes on top of the stack.
572620
for (uint32_t i = 1; i < stateLen; i++) {
573621
mainContent.append("", TextFormatFlag::DontCommit);
574622
}

0 commit comments

Comments
 (0)