#include "lua.hpp"
#include "LuaCodeFormat.h"
#ifdef _MSC_VER
#define EXPORT __declspec(dllexport)
#else
#define EXPORT
#endif
std::string luaToString(lua_State* L, int idx)
{
if (lua_isstring(L, idx))
{
return lua_tostring(L, idx);
}
else if (lua_isinteger(L, idx))
{
return std::to_string(lua_tointeger(L, idx));
}
else if (lua_isnumber(L, idx))
{
return std::to_string(lua_tonumber(L, idx));
}
else if (lua_isboolean(L, idx))
{
return lua_toboolean(L, idx) ? "true" : "false";
}
else
{
return "nil";
}
}
std::string GetDiagnosisString(DiagnosisType type)
{
switch (type)
{
case DiagnosisType::MaxLineWidth: return "MaxLineWidth";
case DiagnosisType::Indent: return "Indent";
case DiagnosisType::Align: return "Align";
case DiagnosisType::Blank: return "Blank";
case DiagnosisType::EndWithNewLine: return "EndWithNewLine";
case DiagnosisType::NameStyle: return "NameStyle";
case DiagnosisType::StatementLineSpace: return "StatementLineSpace";
case DiagnosisType::Spell: return "Spell";
}
return "";
}
int format(lua_State* L)
{
int top = lua_gettop(L);
if (top < 2)
{
return 0;
}
if (lua_isstring(L, 1) && lua_isstring(L, 2))
{
try
{
std::string filename = lua_tostring(L, 1);
std::string text = lua_tostring(L, 2);
LuaCodeFormat::ConfigMap configMap;
if (top == 3 && lua_istable(L, 3))
{
lua_pushnil(L);
while (lua_next(L, -2) != 0)
{
auto key = luaToString(L, -2);
auto value = luaToString(L, -1);
if (key != "nil")
{
configMap.insert({key, value});
}
lua_pop(L, 1);
}
}
auto formattedText = LuaCodeFormat::GetInstance().Reformat(filename, std::move(text), configMap);
if (formattedText.empty())
{
lua_pushboolean(L, false);
return 1;
}
lua_pushboolean(L, true);
lua_pushlstring(L, formattedText.c_str(), formattedText.size());
return 2;
}
catch (std::exception& e)
{
std::string err = e.what();
lua_settop(L, top);
lua_pushboolean(L, false);
lua_pushlstring(L, err.c_str(), err.size());
return 2;
}
}
return 0;
}
enum class UpdateType
{
Created = 1,
Changed = 2,
Deleted = 3
};
int range_format(lua_State* L)
{
int top = lua_gettop(L);
if (top < 4)
{
return 0;
}
if (lua_isstring(L, 1) && lua_isstring(L, 2) && lua_isinteger(L, 3) && lua_isinteger(L, 4))
{
try
{
std::string filename = lua_tostring(L, 1);
std::string text = lua_tostring(L, 2);
int startLine = lua_tointeger(L, 3);
int endLine = lua_tointeger(L, 4);
LuaCodeFormat::ConfigMap configMap;
if (top == 5 && lua_istable(L, 5))
{
lua_pushnil(L);
while (lua_next(L, -2) != 0)
{
auto key = luaToString(L, -2);
auto value = luaToString(L, -1);
if (key != "nil")
{
configMap.insert({key, value});
}
lua_pop(L, 1);
}
}
LuaFormatRange range(startLine, endLine);
auto formattedText = LuaCodeFormat::GetInstance().RangeFormat(filename, range, std::move(text), configMap);
if (formattedText.empty())
{
lua_pushboolean(L, false);
return 1;
}
lua_pushboolean(L, true);
lua_pushlstring(L, formattedText.c_str(), formattedText.size());
lua_pushinteger(L, range.StartLine);
lua_pushinteger(L, range.EndLine);
return 4;
}
catch (std::exception& e)
{
std::string err = e.what();
lua_settop(L, top);
lua_pushboolean(L, false);
lua_pushlstring(L, err.c_str(), err.size());
return 2;
}
}
return 0;
}
int update_config(lua_State* L)
{
int top = lua_gettop(L);
if (top < 3)
{
return 0;
}
if (lua_isinteger(L, 1) && lua_isstring(L, 2) && lua_isstring(L, 3))
{
try
{
auto type = static_cast(lua_tointeger(L, 1));
std::string workspaceUri = lua_tostring(L, 2);
std::string configPath = lua_tostring(L, 3);
switch (type)
{
case UpdateType::Created:
case UpdateType::Changed:
{
LuaCodeFormat::GetInstance().UpdateCodeStyle(workspaceUri, configPath);
break;
}
case UpdateType::Deleted:
{
LuaCodeFormat::GetInstance().RemoveCodeStyle(workspaceUri);
break;
}
}
lua_pushboolean(L, true);
return 1;
}
catch (std::exception& e)
{
std::string err = e.what();
lua_settop(L, top);
lua_pushboolean(L, false);
lua_pushlstring(L, err.c_str(), err.size());
return 2;
}
}
return 0;
}
int diagnose_file(lua_State* L)
{
int top = lua_gettop(L);
if (top < 2)
{
return 0;
}
if (lua_isstring(L, 1) && lua_isstring(L, 2))
{
try
{
std::string filename = lua_tostring(L, 1);
std::string text = lua_tostring(L, 2);
auto result = LuaCodeFormat::GetInstance().Diagnose(filename, std::move(text));
if (!result.first)
{
lua_pushboolean(L, false);
return 1;
}
auto& diagnosticInfos = result.second;
lua_pushboolean(L, true);
int count = 1;
lua_newtable(L);
for (auto& diagnosticInfo : diagnosticInfos)
{
//
lua_newtable(L);
//message
{
lua_pushstring(L, "message");
lua_pushlstring(L, diagnosticInfo.Message.c_str(), diagnosticInfo.Message.size());
lua_rawset(L, -3);
lua_pushstring(L, "type");
lua_pushstring(L, GetDiagnosisString(diagnosticInfo.type).c_str());
lua_rawset(L, -3);
}
// range
{
lua_pushstring(L, "range");
//range table
lua_newtable(L);
lua_pushstring(L, "start");
// start table
lua_newtable(L);
lua_pushstring(L, "line");
lua_pushinteger(L, diagnosticInfo.Range.Start.Line);
lua_rawset(L, -3);
lua_pushstring(L, "character");
lua_pushinteger(L, diagnosticInfo.Range.Start.Character);
lua_rawset(L, -3);
lua_rawset(L, -3); // set start = {}
lua_pushstring(L, "end");
// end table
lua_newtable(L);
lua_pushstring(L, "line");
lua_pushinteger(L, diagnosticInfo.Range.End.Line);
lua_rawset(L, -3);
lua_pushstring(L, "character");
lua_pushinteger(L, diagnosticInfo.Range.End.Character);
lua_rawset(L, -3);
lua_rawset(L, -3); // set end = {}
lua_rawset(L, -3); // set range = {}
}
// lua++count
lua_rawseti(L, -2, count);
count++;
}
return 2;
}
catch (std::exception& e)
{
std::string err = e.what();
lua_settop(L, top);
lua_pushboolean(L, false);
lua_pushlstring(L, err.c_str(), err.size());
return 2;
}
}
return 0;
}
int set_default_config(lua_State* L)
{
int top = lua_gettop(L);
if (top != 1)
{
return 0;
}
if (lua_istable(L, 1))
{
try
{
LuaCodeFormat::ConfigMap configMap;
lua_pushnil(L);
while (lua_next(L, - 2) != 0)
{
auto key = luaToString(L, -2);
auto value = luaToString(L, -1);
if (key != "nil")
{
configMap.insert({key, value});
}
lua_pop(L, 1);
}
LuaCodeFormat::GetInstance().SetDefaultCodeStyle(configMap);
lua_pushboolean(L, true);
return 1;
}
catch (std::exception& e)
{
std::string err = e.what();
lua_settop(L, top);
lua_pushboolean(L, false);
lua_pushlstring(L, err.c_str(), err.size());
return 2;
}
}
return 0;
}
int set_nonstandard_symbol(lua_State* L)
{
int top = lua_gettop(L);
if (top != 2)
{
return 0;
}
if (lua_isstring(L, 1) && lua_istable(L, 2))
{
try
{
std::string type = lua_tostring(L, 1);
std::vector tokens;
lua_pushnil(L);
while (lua_next(L, -2) != 0)
{
auto value = luaToString(L, -1);
tokens.push_back(value);
lua_pop(L, 1);
}
lua_settop(L, top);
LuaCodeFormat::GetInstance().SetSupportNonStandardSymbol(type, tokens);
lua_pushboolean(L, true);
return 1;
}
catch (std::exception& e)
{
std::string err = e.what();
lua_settop(L, top);
lua_pushboolean(L, false);
lua_pushlstring(L, err.c_str(), err.size());
return 2;
}
}
return 0;
}
int spell_load_dictionary_from_path(lua_State* L)
{
int top = lua_gettop(L);
if (top != 1)
{
return 0;
}
if (lua_isstring(L, 1))
{
try
{
auto path = lua_tostring(L, 1);
LuaCodeFormat::GetInstance().LoadSpellDictionary(path);
lua_pushboolean(L, true);
return 1;
}
catch (std::exception& e)
{
std::string err = e.what();
lua_settop(L, top);
lua_pushboolean(L, false);
lua_pushlstring(L, err.c_str(), err.size());
return 2;
}
}
return 0;
}
int spell_load_dictionary_from_buffer(lua_State* L)
{
int top = lua_gettop(L);
if (top != 1)
{
return 0;
}
if (lua_isstring(L, 1))
{
try
{
auto dictionary = lua_tostring(L, 1);
LuaCodeFormat::GetInstance().LoadSpellDictionaryFromBuffer(dictionary);
lua_pushboolean(L, true);
return 1;
}
catch (std::exception& e)
{
std::string err = e.what();
lua_settop(L, top);
lua_pushboolean(L, false);
lua_pushlstring(L, err.c_str(), err.size());
return 2;
}
}
return 0;
}
int spell_analysis(lua_State* L)
{
int top = lua_gettop(L);
if (top < 2)
{
return 0;
}
if (lua_isstring(L, 1) && lua_isstring(L, 2))
{
try
{
std::string filename = lua_tostring(L, 1);
std::string text = lua_tostring(L, 2);
CodeSpellChecker::CustomDictionary tempDict;
if (top == 3 && lua_istable(L, 3))
{
lua_pushnil(L);
while (lua_next(L, -2) != 0)
{
auto value = luaToString(L, -1);
tempDict.insert(value);
lua_pop(L, 1);
}
}
auto diagnosticInfos = LuaCodeFormat::GetInstance().SpellCheck(filename, std::move(text), tempDict);
lua_pushboolean(L, true);
int count = 1;
lua_newtable(L);
for (auto& diagnosticInfo : diagnosticInfos)
{
//
lua_newtable(L);
//message
{
lua_pushstring(L, "message");
lua_pushlstring(L, diagnosticInfo.Message.c_str(), diagnosticInfo.Message.size());
lua_rawset(L, -3);
lua_pushstring(L, "type");
lua_pushstring(L, GetDiagnosisString(diagnosticInfo.type).c_str());
lua_rawset(L, -3);
lua_pushstring(L, "data");
lua_pushstring(L, diagnosticInfo.Data.c_str());
lua_rawset(L, -3);
}
// range
{
lua_pushstring(L, "range");
//range table
lua_newtable(L);
lua_pushstring(L, "start");
// start table
lua_newtable(L);
lua_pushstring(L, "line");
lua_pushinteger(L, diagnosticInfo.Range.Start.Line);
lua_rawset(L, -3);
lua_pushstring(L, "character");
lua_pushinteger(L, diagnosticInfo.Range.Start.Character);
lua_rawset(L, -3);
lua_rawset(L, -3); // set start = {}
lua_pushstring(L, "end");
// end table
lua_newtable(L);
lua_pushstring(L, "line");
lua_pushinteger(L, diagnosticInfo.Range.End.Line);
lua_rawset(L, -3);
lua_pushstring(L, "character");
lua_pushinteger(L, diagnosticInfo.Range.End.Character);
lua_rawset(L, -3);
lua_rawset(L, -3); // set end = {}
lua_rawset(L, -3); // set range = {}
}
// lua++count
lua_rawseti(L, -2, count);
count++;
}
return 2;
}
catch (std::exception& e)
{
std::string err = e.what();
lua_settop(L, top);
lua_pushboolean(L, false);
lua_pushlstring(L, err.c_str(), err.size());
return 2;
}
}
return 0;
}
int spell_suggest(lua_State* L)
{
int top = lua_gettop(L);
if (top != 1)
{
return 0;
}
if (lua_isstring(L, 1))
{
try
{
std::string word = lua_tostring(L, 1);
auto suggests = LuaCodeFormat::GetInstance().SpellCorrect(word);
int count = 1;
lua_newtable(L);
for (auto& suggest : suggests)
{
if (!suggest.Term.empty())
{
lua_pushstring(L, suggest.Term.c_str());
lua_rawseti(L, -2, count);
count++;
}
// 15
if (count == 15)
{
break;
}
}
return 2;
}
catch (std::exception& e)
{
std::string err = e.what();
lua_settop(L, top);
lua_pushboolean(L, false);
lua_pushlstring(L, err.c_str(), err.size());
return 2;
}
}
return 0;
}
static const luaL_Reg lib[] = {
{"format", format},
{"range_format", range_format},
{"update_config", update_config},
{"diagnose_file", diagnose_file},
{"set_default_config", set_default_config},
{"spell_load_dictionary_from_path", spell_load_dictionary_from_path},
{"spell_load_dictionary_from_buffer", spell_load_dictionary_from_buffer},
{"spell_analysis", spell_analysis},
{"spell_suggest", spell_suggest},
{"set_nonstandard_symbol", set_nonstandard_symbol},
{nullptr, nullptr}
};
extern "C"
EXPORT int luaopen_code_format(lua_State* L)
{
luaL_newlibtable(L, lib);
luaL_setfuncs(L, lib, 0);
return 1;
}