1 /*
2  * SPDX-FileCopyrightText: 2020~2020 CSSlayer <wengxt@gmail.com>
3  *
4  * SPDX-License-Identifier: LGPL-2.1-or-later
5  *
6  */
7 #ifndef _FCITX5_LUA_ADDONLOADER_LUAADDONSTATE_H_
8 #define _FCITX5_LUA_ADDONLOADER_LUAADDONSTATE_H_
9 
10 #include "luahelper.h"
11 #include "luastate.h"
12 #include <fcitx/addoninfo.h>
13 #include <fcitx/addonmanager.h>
14 #include <fcitx/instance.h>
15 #include <quickphrase_public.h>
16 
17 namespace fcitx {
18 
19 #define DEFINE_LUA_FUNCTION(FUNCTION_NAME)                                     \
20     static int FUNCTION_NAME(lua_State *lua) {                                 \
21         auto state = GetLuaAddonState(lua);                                    \
22         auto args = LuaCheckArgument(state->state_.get(),                      \
23                                      &LuaAddonState::FUNCTION_NAME##Impl);     \
24         try {                                                                  \
25             auto fn = std::mem_fn(&LuaAddonState::FUNCTION_NAME##Impl);        \
26             auto combined_args = std::tuple_cat(std::make_tuple(state), args); \
27             return LuaReturn(state->state_.get(),                              \
28                              fcitx::callWithTuple(fn, combined_args));         \
29         } catch (const std::exception &e) {                                    \
30             return luaL_error(state->state_, e.what());                        \
31         }                                                                      \
32     }
33 
34 template <typename T>
35 class ScopedSetter {
36 public:
ScopedSetter(T & t,const T & n)37     ScopedSetter(T &t, const T &n) : old_(t), orig_(&t) { t = n; }
38 
~ScopedSetter()39     ~ScopedSetter() { *orig_ = old_; }
40 
41 private:
42     T old_;
43     T *orig_;
44 };
45 
46 using ScopedICSetter = ScopedSetter<TrackableObjectReference<InputContext>>;
47 
48 class EventWatcher {
49 public:
EventWatcher(std::string functionName,std::unique_ptr<HandlerTableEntry<EventHandler>> handler)50     EventWatcher(std::string functionName,
51                  std::unique_ptr<HandlerTableEntry<EventHandler>> handler)
52         : functionName_(std::move(functionName)), handler_(std::move(handler)) {
53     }
54     FCITX_INLINE_DEFINE_DEFAULT_DTOR_AND_MOVE(EventWatcher);
55 
function()56     const auto &function() const { return functionName_; }
57 
58 private:
59     std::string functionName_;
60     std::unique_ptr<HandlerTableEntry<EventHandler>> handler_;
61 };
62 
63 ///
64 // @module fcitx
65 class Converter {
66 public:
Converter(std::string functionName,ScopedConnection connection)67     Converter(std::string functionName, ScopedConnection connection)
68         : functionName_(std::move(functionName)),
69           connection_(std::move(connection)) {}
70     FCITX_INLINE_DEFINE_DEFAULT_DTOR_AND_MOVE(Converter);
71 
function()72     const auto &function() const { return functionName_; }
73 
74 private:
75     std::string functionName_;
76     ScopedConnection connection_;
77 };
78 
79 class LuaAddonState {
80 public:
81     LuaAddonState(Library &luaLibrary, const std::string &name,
82                   const std::string &library, AddonManager *manager);
83 
84     operator LuaState *() { return state_.get(); }
85 
86     RawConfig invokeLuaFunction(InputContext *ic, const std::string &name,
87                                 const RawConfig &config);
88 
89 private:
currentInputContext()90     InputContext *currentInputContext() { return inputContext_.get(); }
91 
92     /// Get the version of fcitx.
93     // @function version
94     // @treturn string The version of fcitx.
95     DEFINE_LUA_FUNCTION(version);
96     /// Get the last committed string.
97     // @function lastCommit
98     // @treturn string The last commit string from fcitx.
99     DEFINE_LUA_FUNCTION(lastCommit);
100     /// a helper function to split the string by delimiter.
101     // @function splitString
102     // @string str string to be split.
103     // @string delim string used as delimiter.
104     // @treturn table An array of string split by delimiter, empty string will
105     // be skipped.
106     DEFINE_LUA_FUNCTION(splitString);
107     /// a helper function to send Debug level log to fcitx.
108     // @function log
109     // @string str log string.
110     DEFINE_LUA_FUNCTION(log);
111     /// Watch for a event from fcitx.
112     // @function watchEvent
113     // @int event Event Type.
114     // @string function the function name.
115     // @return A unique integer identifier.
116     // @see EventType
117     DEFINE_LUA_FUNCTION(watchEvent);
118     /// Unwatch a certain event.
119     // @function unwatchEvent
120     // @int id id of the watcher.
121     // @see watchEvent
122     DEFINE_LUA_FUNCTION(unwatchEvent);
123     /// Return the current input method.
124     // @function currentInputMethod
125     // @treturn string the unique string of current input method.
126     DEFINE_LUA_FUNCTION(currentInputMethod);
127     /// Change the current input method
128     // @function setCurrentInputMethod
129     // @string name the unique string of the input method name.
130     DEFINE_LUA_FUNCTION(setCurrentInputMethod);
131     /// Return the current program name
132     // @function currentProgram
133     // @treturn string the string of current program name.
134     DEFINE_LUA_FUNCTION(currentProgram);
135     /// Add a string converter for committing string.
136     // @function addConverter
137     // @string function the function name.
138     // @treturn int A unique integer identifier.
139     DEFINE_LUA_FUNCTION(addConverter);
140     /// Remove a converter.
141     // @function removeConverter
142     // @int id id of this converter.
143     // @see addConverter
144     DEFINE_LUA_FUNCTION(removeConverter);
145     /// Add a quick phrase handler.
146     // @function addQuickPhraseHandler
147     // @string function the function name.
148     // @treturn int A unique integer identifier.
149     DEFINE_LUA_FUNCTION(addQuickPhraseHandler);
150     /// Remove a quickphrase handler.
151     // @function removeQuickPhraseHandler
152     // @int id id of this handler.
153     // @see addQuickPhraseHandler
154     DEFINE_LUA_FUNCTION(removeQuickPhraseHandler);
155     /// Commit string to current input context.
156     // @function commitString
157     // @string str string to be commit to input context.
158     DEFINE_LUA_FUNCTION(commitString);
159     /// Locate all files with given path and suffix.
160     // @function standardPathLocate
161     // @int type
162     // @string path
163     // @string suffix
164     // @treturn table A table of full file name.
165     // @see StandardPath
166     DEFINE_LUA_FUNCTION(standardPathLocate);
167     /// Helper function to convert UTF16 string to UTF8.
168     // @function UTF16ToUTF8
169     // @string str UTF16 string.
170     // @treturn string UTF8 string or empty string if it fails.
171     DEFINE_LUA_FUNCTION(UTF16ToUTF8)
172     /// Helper function to convert UTF8 string to UTF16.
173     // @function UTF8ToUTF16
174     // @string str UTF8 string.
175     // @treturn string UTF16 string or empty string if it fails.
176     DEFINE_LUA_FUNCTION(UTF8ToUTF16)
177 
178     template <typename T>
179     std::unique_ptr<HandlerTableEntry<EventHandler>> watchEvent(
180         EventType type, int id,
181         std::function<int(std::unique_ptr<LuaState> &, T &)> pushArguments =
182             nullptr,
183         std::function<void(std::unique_ptr<LuaState> &, T &)>
184             handleReturnValue = nullptr);
185 
versionImpl()186     std::tuple<std::string> versionImpl() { return Instance::version(); }
187 
lastCommitImpl()188     std::tuple<std::string> lastCommitImpl() { return lastCommit_; }
189     std::tuple<> logImpl(const char *msg);
190     std::tuple<int> watchEventImpl(int eventType, const char *function);
191     std::tuple<> unwatchEventImpl(int id);
192     std::tuple<std::string> currentInputMethodImpl();
193     std::tuple<> setCurrentInputMethodImpl(const char *str, bool local);
194     std::tuple<std::string> currentProgramImpl();
195 
196     std::tuple<int> addConverterImpl(const char *function);
197     std::tuple<> removeConverterImpl(int id);
198 
199     std::tuple<int> addQuickPhraseHandlerImpl(const char *function);
200     std::tuple<> removeQuickPhraseHandlerImpl(int id);
201 
splitStringImpl(const char * str,const char * delim)202     std::tuple<std::vector<std::string>> splitStringImpl(const char *str,
203                                                          const char *delim) {
204         return stringutils::split(str, delim);
205     }
206 
207     std::tuple<std::string> UTF8ToUTF16Impl(const char *str);
208     std::tuple<std::string> UTF16ToUTF8Impl(const char *str);
209 
210     std::tuple<std::vector<std::string>>
211     standardPathLocateImpl(int type, const char *name, const char *suffix);
212 
213     std::tuple<> commitStringImpl(const char *str);
214     FCITX_ADDON_DEPENDENCY_LOADER(quickphrase, instance_->addonManager());
215 
216     bool handleQuickPhrase(InputContext *ic, const std::string &input,
217                            const QuickPhraseAddCandidateCallback &callback);
218     Instance *instance_;
219     std::unique_ptr<LuaState> state_;
220     TrackableObjectReference<InputContext> inputContext_;
221 
222     std::unordered_map<int, EventWatcher> eventHandler_;
223     std::unordered_map<int, Converter> converter_;
224     std::map<int, std::string> quickphraseHandler_;
225 
226     std::unique_ptr<HandlerTableEntry<QuickPhraseProviderCallback>>
227         quickphraseCallback_;
228     std::unique_ptr<HandlerTableEntry<EventHandler>> commitHandler_;
229 
230     int currentId_ = 0;
231     std::string lastCommit_;
232 };
233 
234 } // namespace fcitx
235 
236 #endif // _FCITX5_LUA_ADDONLOADER_LUAADDONSTATE_H_
237