1 // rime_patch.cc
2 // Foodgen <chen.sst@gmail.com>
3 //
4 #include <iostream>
5 #include <rime_api.h>
6 #include <rime_levers_api.h>
7 #include <rime/common.h>
8 
9 // usage:
10 //   rime_patch config_id key [yaml]
11 // example:
12 //   rime_patch default "menu/page_size" 9
13 //   rime_patch default schema_list/@0/schema combo_pinyin
14 //   rime_patch default schema_list '[{schema: luna_pinyin}]'
15 //   rime_patch default schema_list  # read yaml from stdin
16 
17 using namespace rime;
18 
apply_patch(const string & config_id,const string & key,const string & yaml)19 int apply_patch(const string& config_id,
20                 const string& key, const string& yaml) {
21   RimeApi* rime = rime_get_api();
22   RimeModule* module = rime->find_module("levers");
23   if (!module) {
24     std::cerr << "missing Rime module: levers" << std::endl;
25     return 1;
26   }
27   RimeLeversApi* levers = (RimeLeversApi*)module->get_api();
28 
29   int ret = 1;
30 
31   RimeConfig value = {0};  // should be zero-initialized
32   if (rime->config_load_string(&value, yaml.c_str())) {
33 
34     RimeCustomSettings* settings =
35         levers->custom_settings_init(config_id.c_str(), "rime_patch");
36     levers->load_settings(settings);
37 
38     if (levers->customize_item(settings, key.c_str(), &value)) {
39       levers->save_settings(settings);
40       std::cerr << "patch applied." << std::endl;
41       ret = 0;
42     }
43 
44     levers->custom_settings_destroy(settings);
45     rime->config_close(&value);
46   }
47   else {
48     std::cerr << "bad yaml document." << std::endl;
49   }
50 
51   return ret;
52 }
53 
main(int argc,char * argv[])54 int main(int argc, char *argv[]) {
55   if (argc < 3 || argc > 4) {
56     std::cerr << "usage: " << argv[0] << " config_id key [yaml]" << std::endl;
57     return 1;
58   }
59 
60   RimeApi* rime = rime_get_api();
61 
62   RIME_STRUCT(RimeTraits, traits);
63   traits.app_name = "rime.patch";
64   rime->setup(&traits);
65 
66   rime->deployer_initialize(&traits);
67 
68   string config_id(argv[1]);
69   string key(argv[2]);
70   string yaml;
71   if (argc > 3) {
72     yaml.assign(argv[3]);
73   }
74   else {
75     // read yaml string from stdin
76     yaml.assign((std::istreambuf_iterator<char>(std::cin)),
77                 std::istreambuf_iterator<char>());
78   }
79   int ret = apply_patch(config_id, key, yaml);
80 
81   rime->finalize();
82 
83   return ret;
84 }
85