summaryrefslogtreecommitdiff
path: root/lingucomponent
diff options
context:
space:
mode:
authorMike Kaganski <mike.kaganski@collabora.com>2023-03-09 13:11:14 +0300
committerMike Kaganski <mike.kaganski@collabora.com>2023-03-09 12:08:16 +0000
commit3579343ec00adcbf54938e59d27cc52d11ddb920 (patch)
treeaf7817af468522d033cfdcbfa7b4050570e75793 /lingucomponent
parent33153adfc26e256e3cba27ae8de0ddbbd9f7ce78 (diff)
Some refactoring and deduplication
Change-Id: I443bd562bc9df6636bf71a230a05a12e443c6614 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/148532 Tested-by: Jenkins Reviewed-by: Mike Kaganski <mike.kaganski@collabora.com>
Diffstat (limited to 'lingucomponent')
-rw-r--r--lingucomponent/source/spellcheck/languagetool/languagetoolimp.cxx228
-rw-r--r--lingucomponent/source/spellcheck/languagetool/languagetoolimp.hxx6
2 files changed, 95 insertions, 139 deletions
diff --git a/lingucomponent/source/spellcheck/languagetool/languagetoolimp.cxx b/lingucomponent/source/spellcheck/languagetool/languagetoolimp.cxx
index 91a027e6ec6b..1c167e61df60 100644
--- a/lingucomponent/source/spellcheck/languagetool/languagetoolimp.cxx
+++ b/lingucomponent/source/spellcheck/languagetool/languagetoolimp.cxx
@@ -43,27 +43,23 @@
#include <svtools/languagetoolcfg.hxx>
#include <tools/color.hxx>
#include <tools/long.hxx>
+#include <com/sun/star/text/TextMarkupType.hpp>
#include <com/sun/star/uno/Any.hxx>
#include <comphelper/propertyvalue.hxx>
#include <unotools/lingucfg.hxx>
#include <osl/mutex.hxx>
#include <rtl/uri.hxx>
-using namespace osl;
using namespace com::sun::star;
using namespace com::sun::star::beans;
using namespace com::sun::star::lang;
-using namespace com::sun::star::uno;
using namespace com::sun::star::linguistic2;
-using namespace linguistic;
-
-#define COL_ORANGE Color(0xD1, 0x68, 0x20)
-
-constexpr OUStringLiteral sDuden = u"duden";
namespace
{
-Sequence<PropertyValue> lcl_GetLineColorPropertyFromErrorId(const std::string& rErrorId)
+constexpr size_t MAX_SUGGESTIONS_SIZE = 10;
+
+PropertyValue lcl_GetLineColorPropertyFromErrorId(const std::string& rErrorId)
{
Color aColor;
if (rErrorId == "TYPOS" || rErrorId == "orth")
@@ -77,10 +73,10 @@ Sequence<PropertyValue> lcl_GetLineColorPropertyFromErrorId(const std::string& r
else
{
// Same color is used for other errorId's such as GRAMMAR, TYPOGRAPHY..
+ constexpr Color COL_ORANGE(0xD1, 0x68, 0x20);
aColor = COL_ORANGE;
}
- Sequence<PropertyValue> aProperties{ comphelper::makePropertyValue("LineColor", aColor) };
- return aProperties;
+ return comphelper::makePropertyValue("LineColor", aColor);
}
OString encodeTextForLanguageTool(const OUString& text)
@@ -115,15 +111,14 @@ enum class HTTP_METHOD
HTTP_POST
};
-struct curl_cleanup_t
-{
- void operator()(CURL* p) const { curl_easy_cleanup(p); }
-};
-
-std::string makeHttpRequest_impl(std::string_view aURL, HTTP_METHOD method,
+std::string makeHttpRequest_impl(std::u16string_view aURL, HTTP_METHOD method,
const OString& aPostData, curl_slist* pHttpHeader,
tools::Long& nStatusCode)
{
+ struct curl_cleanup_t
+ {
+ void operator()(CURL* p) const { curl_easy_cleanup(p); }
+ };
std::unique_ptr<CURL, curl_cleanup_t> curl(curl_easy_init());
if (!curl)
{
@@ -139,10 +134,11 @@ std::string makeHttpRequest_impl(std::string_view aURL, HTTP_METHOD method,
+ pVersion->version + " " + pVersion->ssl_version);
(void)curl_easy_setopt(curl.get(), CURLOPT_USERAGENT, useragent.getStr());
+ OString aURL8 = OUStringToOString(aURL, RTL_TEXTENCODING_UTF8);
(void)curl_easy_setopt(curl.get(), CURLOPT_HTTPHEADER, pHttpHeader);
(void)curl_easy_setopt(curl.get(), CURLOPT_FAILONERROR, 1L);
- (void)curl_easy_setopt(curl.get(), CURLOPT_URL, aURL.data());
- (void)curl_easy_setopt(curl.get(), CURLOPT_TIMEOUT, CURL_TIMEOUT);
+ (void)curl_easy_setopt(curl.get(), CURLOPT_URL, aURL8.getStr());
+ (void)curl_easy_setopt(curl.get(), CURLOPT_TIMEOUT, 10L);
// (void)curl_easy_setopt(curl.get(), CURLOPT_VERBOSE, 1L);
std::string response_body;
@@ -174,7 +170,7 @@ std::string makeHttpRequest_impl(std::string_view aURL, HTTP_METHOD method,
return response_body;
}
-std::string makeDudenHttpRequest(std::string_view aURL, const OString& aPostData,
+std::string makeDudenHttpRequest(std::u16string_view aURL, const OString& aPostData,
tools::Long& nStatusCode)
{
struct curl_slist* pList = nullptr;
@@ -192,7 +188,7 @@ std::string makeDudenHttpRequest(std::string_view aURL, const OString& aPostData
return makeHttpRequest_impl(aURL, HTTP_METHOD::HTTP_POST, aPostData, pList, nStatusCode);
}
-std::string makeHttpRequest(std::string_view aURL, HTTP_METHOD method, const OString& aPostData,
+std::string makeHttpRequest(std::u16string_view aURL, HTTP_METHOD method, const OString& aPostData,
tools::Long& nStatusCode)
{
OString realPostData(aPostData);
@@ -208,133 +204,98 @@ std::string makeHttpRequest(std::string_view aURL, HTTP_METHOD method, const OSt
return makeHttpRequest_impl(aURL, method, realPostData, nullptr, nStatusCode);
}
-void parseDudenResponse(ProofreadingResult& rResult, std::string_view aJSONBody)
+template <typename Func>
+Sequence<SingleProofreadingError> parseJson(std::string&& json, std::string path, Func f)
{
- size_t nSize;
- int nProposalSize;
+ std::stringstream aStream(std::move(json)); // Optimized in C++20
boost::property_tree::ptree aRoot;
- std::stringstream aStream(aJSONBody.data());
boost::property_tree::read_json(aStream, aRoot);
- const boost::optional<boost::property_tree::ptree&> aPositions
- = aRoot.get_child_optional("check-positions");
- if (!aPositions || !(nSize = aPositions.get().size()))
- {
- return;
- }
-
- Sequence<SingleProofreadingError> aChecks(nSize);
- auto pChecks = aChecks.getArray();
- size_t nIndex1 = 0, nIndex2 = 0;
- auto itPos = aPositions.get().begin();
- while (itPos != aPositions.get().end())
+ if (auto tree = aRoot.get_child_optional(path))
{
- const boost::property_tree::ptree& rTree = itPos->second;
- const std::string sType = rTree.get<std::string>("type", "");
- const int nOffset = rTree.get<int>("offset", 0);
- const int nLength = rTree.get<int>("length", 0);
-
- pChecks[nIndex1].nErrorStart = nOffset;
- pChecks[nIndex1].nErrorLength = nLength;
- pChecks[nIndex1].nErrorType = PROOFREADING_ERROR;
- //pChecks[nIndex1].aShortComment = ??
- //pChecks[nIndex1].aFullComment = ??
- pChecks[nIndex1].aProperties = lcl_GetLineColorPropertyFromErrorId(sType);
-
- const boost::optional<const boost::property_tree::ptree&> aProposals
- = rTree.get_child_optional("proposals");
- if (aProposals && (nProposalSize = aProposals.get().size()))
+ Sequence<SingleProofreadingError> aErrors(tree->size());
+ auto it = tree->begin();
+ for (auto& rError : asNonConstRange(aErrors))
{
- pChecks[nIndex1].aSuggestions.realloc(std::min(nProposalSize, MAX_SUGGESTIONS_SIZE));
+ f(it->second, rError);
+ it++;
+ }
+ return aErrors;
+ }
+ return {};
+}
- nIndex2 = 0;
- auto itProp = aProposals.get().begin();
- auto pSuggestions = pChecks[nIndex1].aSuggestions.getArray();
- while (itProp != aProposals.get().end() && nIndex2 < MAX_SUGGESTIONS_SIZE)
+void parseDudenResponse(ProofreadingResult& rResult, std::string&& aJSONBody)
+{
+ rResult.aErrors = parseJson(
+ std::move(aJSONBody), "check-positions",
+ [](const boost::property_tree::ptree& rPos, SingleProofreadingError& rError) {
+ rError.nErrorStart = rPos.get<int>("offset", 0);
+ rError.nErrorLength = rPos.get<int>("length", 0);
+ rError.nErrorType = text::TextMarkupType::PROOFREADING;
+ //rError.aShortComment = ??
+ //rError.aFullComment = ??
+ const std::string sType = rPos.get<std::string>("type", {});
+ rError.aProperties = { lcl_GetLineColorPropertyFromErrorId(sType) };
+
+ const auto proposals = rPos.get_child_optional("proposals");
+ if (!proposals)
+ return;
+ rError.aSuggestions.realloc(std::min(proposals->size(), MAX_SUGGESTIONS_SIZE));
+ auto itProp = proposals->begin();
+ for (auto& rSuggestion : asNonConstRange(rError.aSuggestions))
{
- pSuggestions[nIndex2++]
- = OStringToOUString(itProp->second.data(), RTL_TEXTENCODING_UTF8);
+ rSuggestion = OStringToOUString(itProp->second.data(), RTL_TEXTENCODING_UTF8);
itProp++;
}
- }
-
- nIndex1++;
- itPos++;
- }
-
- rResult.aErrors = aChecks;
+ });
}
/*
rResult is both input and output
aJSONBody is the response body from the HTTP Request to LanguageTool API
*/
-void parseProofreadingJSONResponse(ProofreadingResult& rResult, std::string_view aJSONBody)
+void parseProofreadingJSONResponse(ProofreadingResult& rResult, std::string&& aJSONBody)
{
- boost::property_tree::ptree root;
- std::stringstream aStream(aJSONBody.data());
- boost::property_tree::read_json(aStream, root);
- boost::property_tree::ptree& matches = root.get_child("matches");
- size_t matchSize = matches.size();
-
- if (matchSize <= 0)
- {
- return;
- }
- Sequence<SingleProofreadingError> aErrors(matchSize);
- auto pErrors = aErrors.getArray();
- size_t i = 0;
- for (auto it1 = matches.begin(); it1 != matches.end(); it1++, i++)
- {
- const boost::property_tree::ptree& match = it1->second;
- int offset = match.get<int>("offset");
- int length = match.get<int>("length");
- const std::string shortMessage = match.get<std::string>("message");
- const std::string message = match.get<std::string>("shortMessage");
-
- // Parse the error category for Line Color
- const boost::property_tree::ptree& rule = match.get_child("rule");
- const boost::property_tree::ptree& ruleCategory = rule.get_child("category");
- const std::string errorCategoryId = ruleCategory.get<std::string>("id");
-
- OUString aShortComment(shortMessage.c_str(), shortMessage.length(), RTL_TEXTENCODING_UTF8);
- OUString aFullComment(message.c_str(), message.length(), RTL_TEXTENCODING_UTF8);
-
- pErrors[i].nErrorStart = offset;
- pErrors[i].nErrorLength = length;
- pErrors[i].nErrorType = PROOFREADING_ERROR;
- pErrors[i].aShortComment = aShortComment;
- pErrors[i].aFullComment = aFullComment;
- pErrors[i].aProperties = lcl_GetLineColorPropertyFromErrorId(errorCategoryId);
-
- const boost::property_tree::ptree& replacements = match.get_child("replacements");
- int suggestionSize = replacements.size();
-
- if (suggestionSize <= 0)
- {
- continue;
- }
- pErrors[i].aSuggestions.realloc(std::min(suggestionSize, MAX_SUGGESTIONS_SIZE));
- auto pSuggestions = pErrors[i].aSuggestions.getArray();
- // Limit suggestions to avoid crash on context menu popup:
- // (soffice:17251): Gdk-CRITICAL **: 17:00:21.277: ../../../../../gdk/wayland/gdkdisplay-wayland.c:1399: Unable to create Cairo image
- // surface: invalid value (typically too big) for the size of the input (surface, pattern, etc.)
- int j = 0;
- for (auto it2 = replacements.begin(); it2 != replacements.end() && j < MAX_SUGGESTIONS_SIZE;
- it2++, j++)
- {
- const boost::property_tree::ptree& replacement = it2->second;
- std::string replacementStr = replacement.get<std::string>("value");
- pSuggestions[j]
- = OUString(replacementStr.c_str(), replacementStr.length(), RTL_TEXTENCODING_UTF8);
- }
- }
- rResult.aErrors = aErrors;
+ rResult.aErrors = parseJson(
+ std::move(aJSONBody), "matches",
+ [](const boost::property_tree::ptree& match, SingleProofreadingError& rError) {
+ rError.nErrorStart = match.get<int>("offset", 0);
+ rError.nErrorLength = match.get<int>("length", 0);
+ rError.nErrorType = text::TextMarkupType::PROOFREADING;
+ const std::string shortMessage = match.get<std::string>("message", {});
+ const std::string message = match.get<std::string>("shortMessage", {});
+
+ rError.aShortComment = OStringToOUString(shortMessage, RTL_TEXTENCODING_UTF8);
+ rError.aFullComment = OStringToOUString(message, RTL_TEXTENCODING_UTF8);
+
+ // Parse the error category for Line Color
+ std::string errorCategoryId;
+ if (auto rule = match.get_child_optional("rule"))
+ if (auto ruleCategory = rule->get_child_optional("category"))
+ errorCategoryId = ruleCategory->get<std::string>("id", {});
+ rError.aProperties = { lcl_GetLineColorPropertyFromErrorId(errorCategoryId) };
+
+ const auto replacements = match.get_child_optional("replacements");
+ if (!replacements)
+ return;
+ // Limit suggestions to avoid crash on context menu popup:
+ // (soffice:17251): Gdk-CRITICAL **: 17:00:21.277: ../../../../../gdk/wayland/gdkdisplay-wayland.c:1399: Unable to create Cairo image
+ // surface: invalid value (typically too big) for the size of the input (surface, pattern, etc.)
+ rError.aSuggestions.realloc(std::min(replacements->size(), MAX_SUGGESTIONS_SIZE));
+ auto itRep = replacements->begin();
+ for (auto& rSuggestion : asNonConstRange(rError.aSuggestions))
+ {
+ std::string replacementStr = itRep->second.get<std::string>("value", {});
+ rSuggestion = OStringToOUString(replacementStr, RTL_TEXTENCODING_UTF8);
+ itRep++;
+ }
+ });
}
}
LanguageToolGrammarChecker::LanguageToolGrammarChecker()
- : mCachedResults(MAX_CACHE_SIZE)
+ : mCachedResults(10)
{
}
@@ -365,7 +326,7 @@ Sequence<Locale> SAL_CALL LanguageToolGrammarChecker::getLocales()
return m_aSuppLocales;
}
- OString localeUrl = OUStringToOString(rLanguageOpts.getLocaleListURL(), RTL_TEXTENCODING_UTF8);
+ OUString localeUrl = rLanguageOpts.getLocaleListURL();
if (localeUrl.isEmpty())
{
return m_aSuppLocales;
@@ -433,7 +394,7 @@ ProofreadingResult SAL_CALL LanguageToolGrammarChecker::doProofreading(
return xRes;
}
- OString checkerURL = OUStringToOString(rLanguageOpts.getCheckerURL(), RTL_TEXTENCODING_UTF8);
+ OUString checkerURL = rLanguageOpts.getCheckerURL();
if (checkerURL.isEmpty())
{
return xRes;
@@ -463,7 +424,8 @@ ProofreadingResult SAL_CALL LanguageToolGrammarChecker::doProofreading(
OString langTag(LanguageTag::convertToBcp47(aLocale, false).toUtf8());
OString postData = encodeTextForLanguageTool(aText);
- if (rLanguageOpts.getRestProtocol() == sDuden)
+ const bool bDudenProtocol = rLanguageOpts.getRestProtocol() == "duden";
+ if (bDudenProtocol)
{
std::stringstream aStream;
boost::property_tree::ptree aTree;
@@ -488,7 +450,7 @@ ProofreadingResult SAL_CALL LanguageToolGrammarChecker::doProofreading(
tools::Long http_code = 0;
std::string response_body;
- if (rLanguageOpts.getRestProtocol() == sDuden)
+ if (bDudenProtocol)
response_body = makeDudenHttpRequest(checkerURL, postData, http_code);
else
response_body = makeHttpRequest(checkerURL, HTTP_METHOD::HTTP_POST, postData, http_code);
@@ -503,13 +465,13 @@ ProofreadingResult SAL_CALL LanguageToolGrammarChecker::doProofreading(
return xRes;
}
- if (rLanguageOpts.getRestProtocol() == sDuden)
+ if (bDudenProtocol)
{
- parseDudenResponse(xRes, response_body);
+ parseDudenResponse(xRes, std::move(response_body));
}
else
{
- parseProofreadingJSONResponse(xRes, response_body);
+ parseProofreadingJSONResponse(xRes, std::move(response_body));
}
// cache the result
mCachedResults.insert(std::make_pair(postData, xRes.aErrors));
diff --git a/lingucomponent/source/spellcheck/languagetool/languagetoolimp.hxx b/lingucomponent/source/spellcheck/languagetool/languagetoolimp.hxx
index 7827560045ce..93d2c84c612d 100644
--- a/lingucomponent/source/spellcheck/languagetool/languagetoolimp.hxx
+++ b/lingucomponent/source/spellcheck/languagetool/languagetoolimp.hxx
@@ -30,12 +30,6 @@
#include <o3tl/lru_map.hxx>
#include <tools/long.hxx>
-// Magical numbers
-#define MAX_CACHE_SIZE 10
-#define MAX_SUGGESTIONS_SIZE 10
-#define PROOFREADING_ERROR 2
-#define CURL_TIMEOUT 10L
-
class LanguageToolGrammarChecker
: public cppu::WeakImplHelper<css::linguistic2::XProofreader, css::lang::XInitialization,
css::lang::XServiceInfo, css::lang::XServiceDisplayName>