15#include <glibmm/ustring.h>
16#include <pango/pango-attributes.h>
27# include <gtksourceview/gtksource.h>
34 return _format(style, content.c_str());
44 std::ostringstream ost;
47 ost <<
" color=\"" <<
color->raw() <<
'"';
50 ost <<
" bgcolor=\"" <<
background->raw() <<
'"';
53 ost <<
" weight=\"bold\"";
56 ost <<
" font_style=\"italic\"";
59 ost <<
" underline=\"single\"";
63 return Glib::ustring(ost.str());
72Glib::ustring
quote(
const char* text)
74 return Glib::ustring::compose(
"\"%1\"", text);
84 std::string fully_qualified_name(tag_name);
85 if (fully_qualified_name.empty()) {
89 if (fully_qualified_name.find(
':') == std::string::npos) {
90 fully_qualified_name = std::string(
"svg:") + fully_qualified_name;
92 }
else if (fully_qualified_name.find(
"svg:") == 0) {
103 _wip += Glib::ustring::compose(
" %1%2%3",
116 Glib::ustring text = wrap_in_quotes ?
quote(content) : content;
123 auto wrapped = Glib::ustring::compose(
"<!--%1-->", comment);
134 auto manager = gtk_source_style_scheme_manager_get_default();
135 if (
auto scheme = gtk_source_style_scheme_manager_get_scheme(manager, syntax_theme.c_str())) {
137 auto get_color = [](GtkSourceStyle* style,
const char* prop) -> std::optional<Glib::ustring> {
138 std::optional<Glib::ustring> maybe_color;
139 Glib::ustring
name(prop);
142 g_object_get(style, (
name +
"-set").c_str(), &
set,
name.c_str(), &color,
nullptr);
143 if (
set && color && *color ==
'#') {
144 maybe_color = Glib::ustring(color);
150 auto get_bool = [](GtkSourceStyle* style,
const char* prop,
bool def =
false) ->
bool {
151 Glib::ustring
name(prop);
154 g_object_get(style, (
name +
"-set").c_str(), &
set,
name.c_str(), &flag,
nullptr);
155 return set ? !!flag : def;
158 auto get_underline = [](GtkSourceStyle* style,
bool def =
false) ->
bool {
159 Glib::ustring
name(
"underline");
161 PangoUnderline underline;
162 g_object_get(style, (
name +
"-set").c_str(), &
set, (
"pango-" +
name).c_str(), &underline,
nullptr);
163 return set ? underline != PANGO_UNDERLINE_NONE : def;
166 auto to_style = [&](
char const *id) ->
Style {
167 auto s = gtk_source_style_scheme_get_style(scheme,
id);
174 style.
color = get_color(s,
"foreground");
175 style.
background = get_color(s,
"background");
176 style.
bold = get_bool(s,
"bold");
177 style.
italic = get_bool(s,
"italic");
183 styles.
tag_name = to_style(
"def:statement");
186 styles.
content = to_style(
"def:string");
187 styles.
comment = to_style(
"def:comment");
188 styles.
prolog = to_style(
"def:warning");
190 styles.
error = to_style(
"def:error");
202 static auto const colon_without_space = Glib::Regex::create(
":([^\\s\\/])");
203 auto reformatted = colon_without_space->replace(
css, 0,
": \\1", Glib::Regex::MatchFlags::NOTEMPTY);
205 static auto const semicolon_without_newline = Glib::Regex::create(
";([^\r\n])");
206 reformatted = semicolon_without_newline->replace(reformatted, 0,
";\n\\1", Glib::Regex::MatchFlags::NEWLINE_ANYCRLF);
217 static auto const space_after = Glib::Regex::create(
"(:|;)[\\s]+");
218 auto minified = space_after->replace(
css, 0,
"\\1", Glib::Regex::MatchFlags::NEWLINE_ANY);
220 if (
auto const len = minified.size();
len && minified[
len - 1] ==
';') {
221 minified = minified.erase(
len - 1);
232 static auto const space_b4_command = Glib::Regex::create(
"(?<=\\S)\\s*(?=[LHVCSQTAZlhvcsqtaz])");
233 result = space_b4_command->replace(
result, 1,
"\n", Glib::Regex::MatchFlags::NEWLINE_ANY);
236 static auto const space_b4_m = Glib::Regex::create(
"(?<=\\S)\\s*(?=[Mm])");
237 result = space_b4_m->replace(
result, 1,
"\n\n", Glib::Regex::MatchFlags::NEWLINE_ANY);
240 static auto const nospace = Glib::Regex::create(
"([MLHVCSQTAmlhvcsqta])(?=\\S)");
241 return nospace->replace(
result, 0,
"\\1 ", Glib::Regex::MatchFlags::NEWLINE_ANY);
247 static auto const excessive_space = Glib::Regex::create(
"[\\s]+");
248 auto result = excessive_space->replace(d, 0,
" ", Glib::Regex::MatchFlags::NEWLINE_ANY);
256 textview->set_wrap_mode(Gtk::WrapMode::WORD);
257 textview->set_editable(
true);
258 textview->set_visible(
true);
262class PlainTextView :
public TextEditView
266 : _textview(
std::make_unique<
Gtk::TextView>(
Gtk::TextBuffer::
create()))
271 void setStyle(
const Glib::ustring& theme)
override { }
272 void setText(
const Glib::ustring& text)
override { _textview->get_buffer()->set_text(text); }
274 Glib::ustring getText()
const override {
return _textview->get_buffer()->get_text(); }
275 Gtk::TextView& getTextView()
const override {
return *_textview; }
278 std::unique_ptr<Gtk::TextView> _textview;
289 auto default_manager = gtk_source_language_manager_get_default();
290 auto default_paths = gtk_source_language_manager_get_search_path(default_manager);
292 std::vector<char const *> all_paths;
293 for (
auto path = default_paths; *path; path++) {
294 all_paths.push_back(*path);
296 all_paths.push_back(ui_path.c_str());
297 all_paths.push_back(
nullptr);
299 auto result = gtk_source_language_manager_new();
300 gtk_source_language_manager_set_search_path(
result, (gchar **)all_paths.data());
304class SyntaxHighlighting :
public TextEditView
307 SyntaxHighlighting() =
delete;
309 SyntaxHighlighting(
char const*
const language,
310 Glib::ustring (*prettify_func)(Glib::ustring
const &),
311 Glib::ustring (*minify_func)(Glib::ustring
const &))
312 : _prettify{prettify_func}
313 , _minify{minify_func}
315 auto lang = get_language(language);
316 _buffer = gtk_source_buffer_new_with_language(lang);
317 auto view = gtk_source_view_new_with_buffer(_buffer);
322 _textview = std::unique_ptr<Gtk::TextView>(Glib::wrap((GtkTextView*)view));
326 _textview = std::make_unique<Gtk::TextView>(Gtk::TextBuffer::create());
331 ~SyntaxHighlighting()
override { g_object_unref(_buffer); }
333 GtkSourceBuffer *_buffer =
nullptr;
334 std::unique_ptr<Gtk::TextView> _textview;
335 Glib::ustring (*_prettify)(Glib::ustring
const &);
336 Glib::ustring (*_minify)(Glib::ustring
const &);
337 static std::map<std::string, GtkSourceLanguage*> _languages;
340 static GtkSourceLanguage* get_language(
const char* language) {
341 GtkSourceLanguage* lang =
nullptr;
342 auto l = std::string(language);
343 auto it = _languages.find(l);
344 if (it == _languages.end()) {
346 lang = gtk_source_language_manager_get_language(manager, language);
347 _languages[l] = lang;
355 void setStyle(Glib::ustring
const &theme)
override
357 auto manager = gtk_source_style_scheme_manager_get_default();
358 auto scheme = gtk_source_style_scheme_manager_get_scheme(manager, theme.c_str());
359 gtk_source_buffer_set_style_scheme(_buffer, scheme);
363 void setText(Glib::ustring
const &text)
override
365 _textview->get_buffer()->set_text(_prettify(text));
369 Glib::ustring getText()
const override
371 return _minify(_textview->get_buffer()->get_text());
374 Gtk::TextView &getTextView()
const override {
return *_textview; };
377std::map<std::string, GtkSourceLanguage*> SyntaxHighlighting::_languages;
385 auto const no_reformat = [](
auto &s) {
return s; };
388 return std::make_unique<PlainTextView>();
392 return std::make_unique<SyntaxHighlighting>(
"css", no_reformat, no_reformat);
396 return std::make_unique<SyntaxHighlighting>(
"svgpoints", no_reformat, no_reformat);
398 return std::make_unique<SyntaxHighlighting>(
"js", no_reformat, no_reformat);
400 throw std::runtime_error(
"Missing case statement in TetxEditView::create()");
403 return std::make_unique<PlainTextView>();
static std::unique_ptr< TextEditView > create(SyntaxMode mode)
Create a styled text view using the desired syntax highlighting mode.
std::shared_ptr< Css const > css
std::string get_path_string(Domain domain, Type type, char const *filename, char const *extra)
XMLStyles build_xml_styles(const Glib::ustring &syntax_theme)
Build XML styles from a GTKSourceView syntax color theme.
Glib::ustring minify_svgd(Glib::ustring const &d)
Remove excessive space, including newlines, from a path 'd' attibute.
Glib::ustring prettify_css(Glib::ustring const &css)
Reformat CSS for better readability.
static GtkSourceLanguageManager * get_language_manager()
Return a pointer to a language manager which is aware of both default and custom syntaxes.
Glib::ustring quote(const char *text)
Glib::ustring minify_css(Glib::ustring const &css)
Undo the CSS prettification by stripping some whitespace from CSS markup.
Glib::ustring prettify_svgd(Glib::ustring const &d)
Reformat a path 'd' attibute for better readability.
static void init_text_view(Gtk::TextView *textview)
Set default options on a TextView widget used for syntax-colored editing.
SyntaxMode
Syntax highlighting mode (language).
@ CssStyle
File-scope CSS (contents of a CSS file or a <style> tag).
@ PlainText
Plain text (no highlighting).
@ SvgPolyPoints
Contents of the 'points' attribute of <polyline> or <polygon>.
@ SvgPathData
Contents of the 'd' attribute of the SVG <path> element.
@ InlineCss
Inline CSS (contents of a style="..." attribute).
void trim(Glib::ustring &input, Glib::ustring const &also_remove="")
Modifies a string in place, removing leading and trailing whitespace characters.
Inkscape::IO::Resource - simple resource API.
The style of a single element in a (Pango markup)-enabled widget.
std::optional< Glib::ustring > background
Glib::ustring openingTag() const
Get the opening tag of the Pango markup for this style.
std::optional< Glib::ustring > color
Glib::ustring closingTag() const
Get the closing tag of Pango markup for this style.
The styles used for simple XML syntax highlighting.
static bool supportsType(std::string const &id)
Inkscape::Util::trim - trim whitespace and other characters.