Skip to content

Commit 4d0bbe8

Browse files
committed
add Ai page to kdevelop settings
1 parent 562aa6b commit 4d0bbe8

File tree

6 files changed

+252
-1
lines changed

6 files changed

+252
-1
lines changed

kdevcxx_with_ai.desktop

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
[Desktop Entry]
2+
Type=Service
3+
X-KDE-Library=cxx_with_gpt
4+
X-KDE-PluginInfo-Author=Artur Bac
5+
X-KDE-PluginInfo-Email=arturbac.ab@gmail.com
6+
X-KDE-PluginInfo-Name=cxx_with_gpt
7+
X-KDE-PluginInfo-Version=1.0
8+
X-KDE-PluginInfo-Website=http://example.com/plugin
9+
X-KDE-PluginInfo-Category=KDevelop/Plugin
10+
X-KDE-PluginInfo-License=BSL
11+
X-KDE-PluginInfo-Description=OpenAI integration
12+
X-KDE-ServiceTypes=KDevelop/Plugin

src/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ set(kdevcxx_with_ai_SRCS
77
info_dialog.cc
88
plugin_settings.cc
99
markdown_view.cc
10+
kdevcxx_with_ai_config_page.cc
1011
${CXX_WITH_GPT_UI_HEADERS}
1112
)
1213

src/kdevcxx_with_ai.cc

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
// SPDX-License-Identifier: MIT
33

44
#include "kdevcxx_with_ai.h"
5-
5+
#include "kdevcxx_with_ai_config_page.h"
66
// #include <debug.h>
77

88
#include <kpluginfactory.h>
@@ -21,6 +21,7 @@
2121
#include <qtimer.h>
2222
#include <kmessagebox.h>
2323
#include <kdevplatform/interfaces/context.h>
24+
#include <kdevplatform/interfaces/configpage.h>
2425

2526
#ifndef Q_MOC_RUN
2627
#include <aiprocess/app_settings.h>
@@ -217,6 +218,17 @@ auto kdevcxx_with_ai::contextMenuExtension(KDevelop::Context * context, QWidget
217218
return extension;
218219
}
219220

221+
int kdevcxx_with_ai::configPages() const { return 1; }
222+
223+
auto kdevcxx_with_ai::configPage(int number, QWidget * parent) -> KDevelop::ConfigPage *
224+
{
225+
if(number == 0)
226+
return new kdevcxx_with_ai_config_page(this, parent);
227+
return nullptr; // No other pages to return
228+
}
229+
230+
void kdevcxx_with_ai::unload() {}
231+
220232
kdevcxx_with_ai::~kdevcxx_with_ai() {}
221233

222234
#include "kdevcxx_with_ai.moc"

src/kdevcxx_with_ai.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,11 @@ class kdevcxx_with_ai : public KDevelop::IPlugin
3535
auto createActionsForMainWindow(Sublime::MainWindow * window, QString & xmlFile, KActionCollection & actions)
3636
-> void override;
3737

38+
void unload() override;
39+
40+
KDevelop::ConfigPage * configPage(int number, QWidget * parent) override;
41+
int configPages() const override;
42+
3843
private slots:
3944

4045
void on_process_with_ai();

src/kdevcxx_with_ai_config_page.cc

Lines changed: 176 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,176 @@
1+
#include "kdevcxx_with_ai_config_page.h"
2+
#include <klocalizedstring.h>
3+
#include <qboxlayout.h>
4+
#include <qformlayout.h>
5+
#include <qicon.h>
6+
#include <qtabwidget.h>
7+
8+
#ifndef Q_MOC_RUN
9+
#include <aiprocess/app_settings.h>
10+
#include <aiprocess/spdlog.hpp>
11+
#include <simple_enum/enum_cast.hpp>
12+
#include <simple_enum/enum_index.hpp>
13+
#include <aiprocess/log.h>
14+
#endif
15+
16+
template<typename T>
17+
concept callable_with_no_args_returning_void = requires(T t) {
18+
{ t() } -> std::same_as<void>;
19+
};
20+
21+
template<typename WidgetType>
22+
struct config_widget_creator_t
23+
{
24+
QWidget * parent;
25+
QFormLayout * form_layout;
26+
27+
template<callable_with_no_args_returning_void Callable>
28+
auto operator()(QString const & label, Callable emit_changed) const -> WidgetType *
29+
{
30+
auto * widget = new WidgetType(parent);
31+
QObject::connect(widget, &WidgetType::textChanged, parent, emit_changed);
32+
form_layout->addRow(label, widget);
33+
return widget;
34+
}
35+
36+
template<callable_with_no_args_returning_void Callable>
37+
auto operator()(QString const & label, QStringList const & logLevels, Callable emit_changed) const -> WidgetType *
38+
{
39+
auto * widget = new WidgetType(parent);
40+
QObject::connect(
41+
widget, static_cast<void (WidgetType::*)(int)>(&QComboBox::currentIndexChanged), parent, emit_changed
42+
);
43+
form_layout->addRow(label, widget);
44+
widget->addItems(logLevels);
45+
return widget;
46+
}
47+
};
48+
49+
kdevcxx_with_ai_config_page::kdevcxx_with_ai_config_page(KDevelop::IPlugin * plugin, QWidget * parent) :
50+
KDevelop::ConfigPage(plugin, nullptr, parent)
51+
{
52+
QVBoxLayout * main_layout = new QVBoxLayout(this);
53+
QTabWidget * ai_tab_widget = new QTabWidget(this);
54+
main_layout->addWidget(ai_tab_widget);
55+
56+
auto emit_changed = [this]<typename... Args>(Args &&...) { emit changed(); };
57+
// Create a widget to hold the form layout
58+
QWidget * ai_form_widget = new QWidget();
59+
QFormLayout * ai_form_layout = new QFormLayout(ai_form_widget);
60+
61+
openai_key = config_widget_creator_t<QLineEdit>{ai_form_widget, ai_form_layout}("OpenAI Key:", emit_changed);
62+
open_ai_model = config_widget_creator_t<QLineEdit>{ai_form_widget, ai_form_layout}("OpenAI Model:", emit_changed);
63+
language_rules
64+
= config_widget_creator_t<QPlainTextEdit>{ai_form_widget, ai_form_layout}("Language Rules:", emit_changed);
65+
66+
ai_tab_widget->addTab(ai_form_widget, i18n("AI Configuration"));
67+
68+
// second page
69+
70+
QWidget * log_form_widget = new QWidget();
71+
QFormLayout * log_form_layout = new QFormLayout(log_form_widget);
72+
73+
{
74+
config_widget_creator_t<QLineEdit> creator{log_form_widget, log_form_layout};
75+
log_path_edit = creator("Log Path:", emit_changed);
76+
console_log_pattern_edit = creator("Console Log Pattern:", emit_changed);
77+
general_log_pattern_edit = creator("General Log Pattern:", emit_changed);
78+
snippet_log_pattern_edit = creator("Snippet Log Pattern:", emit_changed);
79+
important_log_pattern_edit = creator("Important Log Pattern:", emit_changed);
80+
}
81+
82+
{
83+
QStringList logLevels = {"trace", "debug", "info", "warn", "error", "critical"};
84+
config_widget_creator_t<QComboBox> creator{log_form_widget, log_form_layout};
85+
console_log_level_combo = creator("Console Log Pattern:", logLevels, emit_changed);
86+
general_log_level_combo = creator("General Log Level:", logLevels, emit_changed);
87+
snippet_log_level_combo = creator("Snippet Log Pattern:", logLevels, emit_changed);
88+
important_log_level_combo = creator("Important Log Pattern:", logLevels, emit_changed);
89+
}
90+
91+
flush_every_spin = new QSpinBox(log_form_widget);
92+
flush_every_spin->setMinimum(1);
93+
flush_every_spin->setMaximum(60);
94+
flush_every_spin->setValue(3);
95+
log_form_layout->addRow(i18n("Flush Every (seconds):"), flush_every_spin);
96+
97+
activation_keys_spin = new QSpinBox(log_form_widget);
98+
activation_keys_spin->setMinimum(0);
99+
activation_keys_spin->setMaximum(std::numeric_limits<int>::max());
100+
log_form_layout->addRow(i18n("Activation Keys:"), activation_keys_spin);
101+
102+
ai_tab_widget->addTab(log_form_widget, i18n("Logging"));
103+
reset();
104+
}
105+
106+
QString kdevcxx_with_ai_config_page::name() const { return i18n("OpenAI Configuration"); }
107+
108+
QString kdevcxx_with_ai_config_page::fullName() const { return i18n("Configure Open AI Settings"); }
109+
110+
QIcon kdevcxx_with_ai_config_page::icon() const { return QIcon::fromTheme("preferences-other"); }
111+
112+
void kdevcxx_with_ai_config_page::apply()
113+
{
114+
aiprocess::debug("apply() called");
115+
aiprocess::store_ai_settings(aiprocess::ai_settings_t{
116+
.api_key = openai_key->text().toStdString(),
117+
.cxx_rules = language_rules->toPlainText().toStdString(),
118+
.gpt_model = open_ai_model->text().toStdString()
119+
});
120+
using level_enum = aiprocess::app_settings_t::level_enum;
121+
aiprocess::store_app_settings(aiprocess::app_settings_t{
122+
.log_path = log_path_edit->text().toStdString(),
123+
.console_log_pattern = console_log_pattern_edit->text().toStdString(),
124+
.general_log_pattern = general_log_pattern_edit->text().toStdString(),
125+
.snippet_log_pattern = snippet_log_pattern_edit->text().toStdString(),
126+
.important_log_pattern = important_log_pattern_edit->text().toStdString(),
127+
.console_log_level = level_enum(console_log_level_combo->currentIndex()),
128+
.general_log_level = level_enum(general_log_level_combo->currentIndex()),
129+
.snippet_log_level = level_enum(snippet_log_level_combo->currentIndex()),
130+
.important_log_level = level_enum(important_log_level_combo->currentIndex()),
131+
.activation_keys = activation_keys_spin->value()
132+
});
133+
}
134+
135+
void kdevcxx_with_ai_config_page::reset()
136+
{
137+
aiprocess::debug("reset() called");
138+
{
139+
aiprocess::ai_settings_t settings = aiprocess::load_ai_settings();
140+
language_rules->setPlainText(QString::fromStdString(settings.cxx_rules));
141+
openai_key->setText(QString::fromStdString(settings.api_key));
142+
open_ai_model->setText(QString::fromStdString(settings.gpt_model));
143+
}
144+
145+
// Second page settings
146+
147+
{
148+
aiprocess::app_settings_t settings{aiprocess::load_app_settings()};
149+
log_path_edit->setText(QString::fromStdString(settings.log_path));
150+
console_log_pattern_edit->setText(QString::fromStdString(settings.console_log_pattern));
151+
general_log_pattern_edit->setText(QString::fromStdString(settings.general_log_pattern));
152+
snippet_log_pattern_edit->setText(QString::fromStdString(settings.snippet_log_pattern));
153+
important_log_pattern_edit->setText(QString::fromStdString(settings.important_log_pattern));
154+
155+
auto set_combo_index = [](QComboBox * comboBox, auto enumValue)
156+
{
157+
auto ix{simple_enum::enum_index(enumValue)};
158+
if(ix.has_value())
159+
comboBox->setCurrentIndex(*ix);
160+
};
161+
set_combo_index(console_log_level_combo, settings.console_log_level);
162+
set_combo_index(general_log_level_combo, settings.general_log_level);
163+
set_combo_index(snippet_log_level_combo, settings.snippet_log_level);
164+
set_combo_index(important_log_level_combo, settings.important_log_level);
165+
166+
activation_keys_spin->setValue(settings.activation_keys);
167+
}
168+
}
169+
170+
void kdevcxx_with_ai_config_page::defaults()
171+
{
172+
aiprocess::debug("defaults() called");
173+
language_rules->setPlainText(QString::fromUtf8(aiprocess::default_ai_rules.data(), aiprocess::default_ai_rules.size())
174+
);
175+
open_ai_model->setText(QString::fromUtf8(aiprocess::default_gpt_model.data(), aiprocess::default_gpt_model.size()));
176+
}

src/kdevcxx_with_ai_config_page.h

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
#pragma once
2+
3+
#include <kdevplatform/interfaces/configpage.h>
4+
#include <qwidget.h>
5+
#include <qlineedit.h>
6+
#include <qlabel.h>
7+
#include <qcombobox.h>
8+
#include <qspinbox.h>
9+
#include <qplaintextedit.h>
10+
11+
class kdevcxx_with_ai_config_page : public KDevelop::ConfigPage
12+
{
13+
Q_OBJECT
14+
15+
public:
16+
explicit kdevcxx_with_ai_config_page(KDevelop::IPlugin * plugin, QWidget * parent = nullptr);
17+
18+
QString name() const override;
19+
QString fullName() const override;
20+
QIcon icon() const override;
21+
22+
void apply() override;
23+
void reset() override;
24+
void defaults() override;
25+
26+
private:
27+
QPlainTextEdit * language_rules;
28+
QLineEdit * openai_key;
29+
QLineEdit * open_ai_model;
30+
31+
QLineEdit * log_path_edit;
32+
QLineEdit * console_log_pattern_edit;
33+
QLineEdit * general_log_pattern_edit;
34+
QLineEdit * snippet_log_pattern_edit;
35+
QLineEdit * important_log_pattern_edit;
36+
37+
QComboBox * console_log_level_combo;
38+
QComboBox * general_log_level_combo;
39+
QComboBox * snippet_log_level_combo;
40+
QComboBox * important_log_level_combo;
41+
42+
QSpinBox * flush_every_spin;
43+
QSpinBox * activation_keys_spin;
44+
};
45+

0 commit comments

Comments
 (0)