Fcitx
configuration.cpp
1 /*
2  * SPDX-FileCopyrightText: 2015-2015 CSSlayer <wengxt@gmail.com>
3  *
4  * SPDX-License-Identifier: LGPL-2.1-or-later
5  *
6  */
7 
8 #include "configuration.h"
9 #include <algorithm>
10 #include <cassert>
11 #include <list>
12 #include <memory>
13 #include <stdexcept>
14 #include <unordered_map>
16 
17 namespace fcitx {
19 public:
20  std::list<std::string> optionsOrder_;
21  std::unordered_map<std::string, OptionBase *> options_;
22 };
23 
24 Configuration::Configuration()
25  : d_ptr(std::make_unique<ConfigurationPrivate>()) {}
26 
27 Configuration::~Configuration() = default;
28 
29 void Configuration::dumpDescription(RawConfig &config) const {
30  return dumpDescriptionImpl(config, {});
31 }
32 
33 void Configuration::dumpDescriptionImpl(
34  RawConfig &config, const std::vector<std::string> &parentPaths) const {
35  FCITX_D();
36  auto fullpaths = parentPaths;
37  fullpaths.push_back(typeName());
38  auto pathString = stringutils::join(fullpaths, '$');
39  std::shared_ptr<RawConfig> subRoot = config.get(pathString, true);
40  std::vector<
41  std::tuple<std::vector<std::string>, std::unique_ptr<Configuration>>>
42  subConfigs;
43  for (const auto &path : d->optionsOrder_) {
44  auto optionIter = d->options_.find(path);
45  assert(optionIter != d->options_.end());
46  auto *option = optionIter->second;
47  if (option->skipDescription()) {
48  continue;
49  }
50  auto descConfigPtr = subRoot->get(option->path(), true);
51  option->dumpDescription(*descConfigPtr);
52 
53  auto subConfig = option->subConfigSkeleton();
54  if (subConfig) {
55  auto subConfigPath = parentPaths;
56  subConfigPath.push_back(option->path());
57  std::string subTypeName = subConfig->typeName();
58  const auto *oldTypeName = descConfigPtr->valueByPath("Type");
59  // Replace the "Type" with the full name we want.
60  // Path$To$Value$TypeName
61  if (oldTypeName && oldTypeName->ends_with(subTypeName)) {
62  auto newTypeName = oldTypeName->substr(
63  0, oldTypeName->size() - subTypeName.size());
64  newTypeName.append(stringutils::join(subConfigPath, '$'));
65  newTypeName.append("$");
66  newTypeName.append(subTypeName);
67  descConfigPtr->setValueByPath("Type", std::move(newTypeName));
68  }
69  subConfigs.emplace_back(subConfigPath, std::move(subConfig));
70  }
71  }
72 
73  // Make sure sub type use an unique name, named after the path to the value.
74  for (const auto &[subConfigPath, subConfigPtr] : subConfigs) {
75  subConfigPtr->dumpDescriptionImpl(config, subConfigPath);
76  }
77 }
78 
79 bool Configuration::compareHelper(const Configuration &other) const {
80  FCITX_D();
81  return std::all_of(
82  d->optionsOrder_.begin(), d->optionsOrder_.end(),
83  [d, &other](const auto &path) {
84  auto optionIter = d->options_.find(path);
85  assert(optionIter != d->options_.end());
86  auto otherOptionIter = other.d_func()->options_.find(path);
87  assert(otherOptionIter != other.d_func()->options_.end());
88  return *optionIter->second == *otherOptionIter->second;
89  });
90  return true;
91 }
92 
93 void Configuration::copyHelper(const Configuration &other) {
94  FCITX_D();
95  for (const auto &path : d->optionsOrder_) {
96  auto optionIter = d->options_.find(path);
97  assert(optionIter != d->options_.end());
98  auto otherOptionIter = other.d_func()->options_.find(path);
99  assert(otherOptionIter != other.d_func()->options_.end());
100  optionIter->second->copyFrom(*otherOptionIter->second);
101  }
102 }
103 
104 void Configuration::load(const RawConfig &config, bool partial) {
105  FCITX_D();
106  for (const auto &path : d->optionsOrder_) {
107  auto subConfigPtr = config.get(path);
108  auto *option = d->options_[path];
109  if (!subConfigPtr) {
110  if (!partial) {
111  option->reset();
112  }
113  continue;
114  }
115  if (!option->unmarshall(*subConfigPtr, partial)) {
116  option->reset();
117  }
118  }
119 }
120 
121 void Configuration::save(RawConfig &config) const {
122  FCITX_D();
123  for (const auto &path : d->optionsOrder_) {
124  auto iter = d->options_.find(path);
125  assert(iter != d->options_.end());
126  if (iter->second->skipSave()) {
127  continue;
128  }
129  auto subConfigPtr = config.get(path, true);
130  iter->second->marshall(*subConfigPtr);
131  subConfigPtr->setComment(iter->second->description());
132  }
133 }
134 
135 void Configuration::addOption(OptionBase *option) {
136  FCITX_D();
137  if (d->options_.count(option->path())) {
138  throw std::logic_error("Duplicate option path");
139  }
140 
141  d->optionsOrder_.push_back(option->path());
142  d->options_[option->path()] = option;
143 }
144 
146  FCITX_D();
147  for (const auto &path : d->optionsOrder_) {
148  auto iter = d->options_.find(path);
149  assert(iter != d->options_.end());
150  // Unfortunately on certain system OptionBaseV2 doesn't have key
151  // function emit type info, so we have to add OptionBaseV3 with a
152  // non-abstract virtual function.
153  if (auto *optionV3 = dynamic_cast<OptionBaseV3 *>(iter->second)) {
154  optionV3->syncDefaultValueToCurrent();
155  } else if (auto *optionV2 =
156  dynamic_cast<OptionBaseV2 *>(iter->second)) {
157  optionV2->syncDefaultValueToCurrent();
158  }
159  }
160 }
161 
162 } // namespace fcitx
Definition: action.cpp:17
void load(const RawConfig &config, bool partial=false)
Load configuration from RawConfig.
void syncDefaultValueToCurrent()
Set default value to current value.
String handle utilities.
std::string join(Iter start, Iter end, T &&delim)
Join a range of string with delim.
Definition: stringutils.h:109