1 | // SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd. |
2 | // |
3 | // SPDX-License-Identifier: GPL-3.0-or-later |
4 | |
5 | #include "common/common.h" |
6 | #include "jsonrpccallproxy.h" |
7 | #include "remotechecker.h" |
8 | |
9 | #include <QCoreApplication> |
10 | #include <QDebug> |
11 | #include <QJsonObject> |
12 | #include <QDir> |
13 | |
14 | #include <iostream> |
15 | |
16 | // setting from clangd trismit |
17 | QProcess *createCxxServ(const newlsp::ProjectKey &key) |
18 | { |
19 | lspServOut << __FUNCTION__ << qApp->thread() << QThread::currentThread(); |
20 | if (key.language != newlsp::Cxx) |
21 | return nullptr; |
22 | |
23 | QString projectCacheDir = ".unioncode" ; |
24 | QString compileDB_Path = QString::fromStdString(key.workspace) + QDir::separator() + projectCacheDir; |
25 | QStringList compileDB_CMD_As; |
26 | compileDB_CMD_As << "-S" << QString::fromStdString(key.workspace); |
27 | compileDB_CMD_As << "-B" << compileDB_Path; |
28 | compileDB_CMD_As << "-DCMAKE_EXPORT_COMPILE_COMMANDS=1" ; |
29 | QProcess::execute("/usr/bin/cmake" , compileDB_CMD_As); |
30 | |
31 | QStringList procAs; |
32 | QString clangd = "clangd-13" ; |
33 | if (ProcessUtil::exists(clangd)) { |
34 | procAs << clangd; |
35 | } else { |
36 | QString clangdFileName = "clangd" ; |
37 | if (!env::pkg::native::installed()) { |
38 | RemoteChecker::instance().checkLanguageBackend(QString::fromStdString(key.language)); |
39 | QString runtimePath = CustomPaths::lspRuntimePath(QString::fromStdString(key.language)); |
40 | procAs << runtimePath + QDir::separator() + clangdFileName; |
41 | } else { |
42 | procAs << env::pkg::native::path(clangdFileName); |
43 | } |
44 | } |
45 | |
46 | procAs << "--log=verbose" ; |
47 | procAs << QString("--compile-commands-dir=%0" ).arg(compileDB_Path); |
48 | procAs << "--clang-tidy" ; |
49 | procAs << "-j=$(nproc)" ; |
50 | |
51 | auto proc = new QProcess(); |
52 | proc->setProgram("/usr/bin/bash" ); |
53 | proc->setArguments({"-c" , procAs.join(" " )}); |
54 | |
55 | return proc; |
56 | } |
57 | |
58 | // setting from jdtls trismit |
59 | QProcess *createJavaServ(const newlsp::ProjectKey &key) |
60 | { |
61 | lspServOut << __FUNCTION__ << qApp->thread() << QThread::currentThread(); |
62 | if (key.language != newlsp::Java) |
63 | return nullptr; |
64 | |
65 | QString dataDir = CustomPaths::projectCachePath(QString::fromStdString(key.workspace)); |
66 | QString runtimePath = CustomPaths::lspRuntimePath(QString::fromStdString(key.language)); |
67 | bool noRuntimeChilds = QDir(runtimePath).entryList(QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot).isEmpty(); |
68 | if (noRuntimeChilds) { |
69 | if (!env::pkg::native::installed()) { |
70 | RemoteChecker::instance().checkLanguageBackend(QString::fromStdString(key.language)); |
71 | } else { |
72 | lspServOut << "unzip install native package..." << noRuntimeChilds; |
73 | QString jdtlsNativePkgPath = env::pkg::native::path(env::package::Category::get()->jdtls); |
74 | ProcessUtil::execute("tar" , {"zxvf" , jdtlsNativePkgPath, "-C" , "." }, runtimePath, |
75 | [=](const QByteArray &data){ |
76 | lspServOut << QString(data); |
77 | }); |
78 | } |
79 | } |
80 | |
81 | auto proc = new QProcess(); |
82 | QString lanuchLine = "/usr/bin/java " |
83 | "-Declipse.application=org.eclipse.jdt.ls.core.id1 " |
84 | "-Dosgi.bundles.defaultStartLevel=4 " |
85 | "-Declipse.product=org.eclipse.jdt.ls.core.product " |
86 | "-Dlog.level=ALL " |
87 | "-noverify " |
88 | "-Xmx1G " |
89 | "--add-modules=ALL-SYSTEM " |
90 | "--add-opens java.base/java.util=ALL-UNNAMED " |
91 | "--add-opens java.base/java.lang=ALL-UNNAMED " |
92 | "-jar " + runtimePath + "/plugins/org.eclipse.equinox.launcher_1.6.400.v20210924-0641.jar " |
93 | "-configuration " + runtimePath + "/config_linux " |
94 | + QString("-data %0" ).arg(dataDir); |
95 | proc->setProgram("/usr/bin/bash" ); |
96 | proc->setArguments({"-c" , lanuchLine}); |
97 | |
98 | return proc; |
99 | } |
100 | |
101 | // setting from pyls trismit |
102 | QProcess *createPythonServ(const newlsp::ProjectKey &key) |
103 | { |
104 | lspServOut << __FUNCTION__ << qApp->thread() << QThread::currentThread(); |
105 | if (key.language != newlsp::Python) |
106 | return nullptr; |
107 | |
108 | QString jdtlsNativePkgPath = env::pkg::native::path(env::package::Category::get()->jdtls); |
109 | ProcessUtil::execute("pip3" , {"install" , "python-language-server[all]" }, [=](const QByteArray &data){ |
110 | lspServOut << QString(data); |
111 | }); |
112 | |
113 | auto proc = new QProcess(); |
114 | proc->setProgram("/usr/bin/bash" ); |
115 | proc->setArguments({"-c" ,"pyls -v" }); |
116 | env::lang::Version pyVer; |
117 | pyVer.major = 3; |
118 | if (!ProcessUtil::exists("pyls" )) { |
119 | auto python3Env = env::lang::get(env::lang::Category::User, env::lang::Python, pyVer); |
120 | proc->setProcessEnvironment(python3Env); |
121 | } |
122 | |
123 | return proc; |
124 | } |
125 | |
126 | // setting from pyls trismit |
127 | QProcess *createJSServ(const newlsp::ProjectKey &key) |
128 | { |
129 | lspServOut << "create js language server," << qApp->thread() << QThread::currentThread(); |
130 | if (key.language != newlsp::JS) |
131 | return nullptr; |
132 | |
133 | QString jsServerInstallPath = CustomPaths::lspRuntimePath(QString::fromStdString(key.language)); |
134 | RemoteChecker::instance().checkJSServer(jsServerInstallPath); |
135 | |
136 | QString nodePath = jsServerInstallPath + "/node_modules/node/bin/node" ; |
137 | QString serverPath = jsServerInstallPath + "/node_modules/.bin/typescript-language-server" ; |
138 | if (!QFileInfo::exists(nodePath) || !QFileInfo::exists(serverPath)) { |
139 | return nullptr; |
140 | } |
141 | |
142 | auto proc = new QProcess(); |
143 | proc->setProgram(nodePath); |
144 | proc->setArguments({serverPath, "--stdio" }); |
145 | |
146 | return proc; |
147 | } |
148 | |
149 | |
150 | void selectLspServer(const QJsonObject ¶ms) |
151 | { |
152 | QString language = params.value(QString::fromStdString(newlsp::language)).toString(); |
153 | QString workspace = params.value(QString::fromStdString(newlsp::workspace)).toString(); |
154 | newlsp::ProjectKey projectKey {language.toStdString(), workspace.toStdString()}; |
155 | JsonRpcCallProxy::ins().setSelect(projectKey); |
156 | QProcess *proc = JsonRpcCallProxy::ins().value(projectKey); |
157 | |
158 | if (!proc) { |
159 | proc = JsonRpcCallProxy::ins().createLspServ(projectKey); |
160 | if (proc) { |
161 | proc->setProcessChannelMode(QProcess::ForwardedOutputChannel); |
162 | QObject::connect(proc, &QProcess::readyReadStandardError, proc, [=]() { |
163 | lspServErr << "run lspServ error:" << proc->readAllStandardError().toStdString(); |
164 | }); |
165 | proc->start(); |
166 | lspServOut << "save backend process" ; |
167 | JsonRpcCallProxy::ins().save(projectKey, proc); |
168 | lspServOut << "selected ProjectKey{language:" << projectKey.language |
169 | << ", workspace:" << projectKey.workspace << "}" ; |
170 | JsonRpcCallProxy::ins().setSelect(projectKey); |
171 | } |
172 | } |
173 | |
174 | if (!proc) |
175 | lspServOut << "selected error ProjectKey{language:" << projectKey.language |
176 | << ",workspace:" << projectKey.workspace << "}" ; |
177 | } |
178 | |
179 | int main(int argc, char *argv[]) |
180 | { |
181 | QCoreApplication a(argc, argv); |
182 | |
183 | JsonRpcCallProxy::ins().bindCreateProc(newlsp::Cxx, createCxxServ); |
184 | JsonRpcCallProxy::ins().bindCreateProc(newlsp::Java, createJavaServ); |
185 | JsonRpcCallProxy::ins().bindCreateProc(newlsp::Python, createPythonServ); |
186 | JsonRpcCallProxy::ins().bindCreateProc(newlsp::JS, createJSServ); |
187 | JsonRpcCallProxy::ins().bindFilter("selectLspServer" , selectLspServer); |
188 | |
189 | newlsp::ServerApplication lspServ(a); |
190 | QObject::connect(&lspServ, &newlsp::ServerApplication::jsonrpcMethod, |
191 | &JsonRpcCallProxy::ins(), &JsonRpcCallProxy::methodFilter, |
192 | Qt::QueuedConnection); |
193 | |
194 | QObject::connect(&lspServ, &newlsp::ServerApplication::jsonrpcNotification, |
195 | &JsonRpcCallProxy::ins(), &JsonRpcCallProxy::notificationFilter, |
196 | Qt::QueuedConnection); |
197 | lspServ.start(); |
198 | lspServOut << "created ServerApplication" ; |
199 | |
200 | return a.exec(); |
201 | } |
202 | |