Adds help document, adds block quote support, updates gemini parser to newest spec, adds support for arbitrary gemini files in about: space, adds url bar shortcut, fixes bug with line breaks in preformatted text

This commit is contained in:
Felix (xq) Queißner 2020-06-09 00:19:32 +02:00
parent 573e73eb1b
commit df4fbcb4cf
18 changed files with 246 additions and 24 deletions

View File

@ -17,6 +17,12 @@ Kristall Changelog
- Added progress display in status bar with loading time and already transferred bytes
- Added support for finger:// protocol
- Added experimental *highlighting* and _underlining_ for text/gemini
- Desktop file is provided for integrating with XDG
- Fixed bug: Preformatted lines don't break anymore
- text/gemini parsing updated
- Added support for block quotes
- Added help file
- Added shortcut to focus URL bar
== 0.1
- Initial release

View File

@ -44,7 +44,7 @@ A high-quality visual cross-platform gemini browser.
![Site Theme](https://mq32.de/public/7123e22a58969448c27b24df8510f4d56921bf23.png)
## Build Instructions
## Build/Install Instructions
### Requirements
@ -52,7 +52,7 @@ A high-quality visual cross-platform gemini browser.
### Build
## *nix
#### *nix
There's a small `Makefile` provided that does all necessary steps and creates a build directory, then copies the build artifact from the build directory. Just do `make` in the root directory, it should work.
@ -69,7 +69,7 @@ make
- It seems like Qt wants `libzstd.so.3.1` instead of `libzstd.so.3.2`. Just symlink that file into the build directory
- Use `make` and not `gmake` to build the project.
### Notes for Ubuntu 20.04:
##### Notes for Ubuntu 20.04:
- Requires packages
- `qt5-default`
- `qt5-qmake`
@ -77,18 +77,27 @@ make
- `make`
- `g++`
### Notes for Manjaro/Arch
##### Notes for Manjaro/Arch
- Requires packages
- `qt5`
- `qt5-multimedia`
### Notes on void linux
##### Notes on void linux
- set env variable `QT_SELECT=5`
## Windows
#### Windows
Just use QtCreator to build `./src/kristall.pro`. Default settings should be fine.
### Manual Installation
#### Unix / XDG
The provided desktop file can be installed into the local system
```sh
ln -s Kristall.desktop ~/.local/share/applications/kristall.desktop
```
## TODO
- [ ] Survive full torture suite
- [ ] Correctly parse mime parameters

Binary file not shown.

After

Width:  |  Height:  |  Size: 179 KiB

View File

@ -0,0 +1,27 @@
```
,`.
,'` | _.-.
,` | ,',' /
: | ,',' ;
\ : / / /
\ `.' ( ,'
,'' _ `.
,' (o_) `\
. (,.) _.-- :
-..`/( .-'_..- `|
.-'\,`. `-._ ;
`._ /__
,':)-.._ _.(:::`.
|'\ / /`:::|
,' \ : : : `:|
/ : | | | \
: | | : :..---.:
| | ; ,`._`-.|_ `.
| |' ,'._ `. `. |_\
| : /`-. `. `. `. :
: \ : __ `. `. `. \ ;
\ \ |. / `. \ \ /
|\ `..: `. __ \ \ /
' ` .:::::\ `. / \ \,'
.::::::::::-..'_..-' SSt
```

44
src/about/help.gemini Normal file
View File

@ -0,0 +1,44 @@
# Kristall Help
This is the manual for the Kristall small-internet browser. It contains explanations on how to use the program, what each setting means and
## The Mission
Kristall tries to fill the hole of graphical browsers for alternative internet protocols with a high usability and feature richness.
## Protocol support
These protocols are currently supported via their respective URL schemes:
=> https://gemini.circumlunar.space/ Gemini
=> https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol HTTP/HTTPS
=> https://en.wikipedia.org/wiki/Gopher_(protocol) Gopher
=> https://en.wikipedia.org/wiki/Finger_protocol Finger
### Built-in sites
There is also the scheme about: which can be used to access internal sites for configuration, usability or help (this is one of them!):
=> about:blank
=> about:favourites
=> about:help
## Shortcuts
- Ctrl+T ⇒ New tab
- Ctrl+W ⇒ Close tab
- Ctrl+D ⇒ Quick add/remove from favourites
- Ctrl+L ⇒ Focus URL bar
- Ctrl+S ⇒ Save current file
- Ctrl+H ⇒ Go to home page
- Alt+Left ⇒ Navigate one page back
- Alt+Right ⇒ Navigate one page forward
- F1 ⇒ View this document
- F5 ⇒ Refresh current tab
## Contact me
I'm eager to hear from your experience! Did everything work? Is something especially cool or bad? Tell me what you think or what annoys you!
Please note that everything here is still work-in-progress and may crash!
Mail: kristall@mq32.de
GitHub: https://github.com/MasterQ32/kristall

View File

@ -166,7 +166,15 @@ void BrowserTab::navigateTo(const QUrl &url, PushToHistory mode)
}
else
{
QMessageBox::warning(this, "Kristall", "Unknown location: " + url.path());
QFile file(QString(":/about/%1.gemini").arg(url.path()));
if(file.open(QFile::ReadOnly))
{
this->on_requestComplete(file.readAll(), "text/gemini");
}
else
{
QMessageBox::warning(this, "Kristall", "Unknown location: " + url.path());
}
}
}
@ -233,6 +241,12 @@ void BrowserTab::toggleIsFavourite(bool isFavourite)
this->updateUI();
}
void BrowserTab::focusUrlBar()
{
this->ui->url_bar->setFocus(Qt::ShortcutFocusReason);
this->ui->url_bar->selectAll();
}
void BrowserTab::on_url_bar_returnPressed()
{
QUrl url { this->ui->url_bar->text() };

View File

@ -54,6 +54,8 @@ public:
void toggleIsFavourite(bool isFavourite);
void focusUrlBar();
signals:
void titleChanged(QString const & title);
void locationChanged(QUrl const & url);

View File

@ -125,6 +125,7 @@ DocumentStyle::DocumentStyle() : theme(Fixed),
h1_color("#022f90"),
h2_color("#022f90"),
h3_color("#022f90"),
blockquote_color("#FFFFFF"),
internal_link_color("#0e8fff"),
external_link_color("#0e8fff"),
cross_scheme_link_color("#0960a7"),
@ -164,6 +165,7 @@ bool DocumentStyle::save(QSettings &settings) const
settings.setValue("background_color", background_color.name());
settings.setValue("standard_color", standard_color.name());
settings.setValue("preformatted_color", preformatted_color.name());
settings.setValue("blockquote_color", blockquote_color.name());
settings.setValue("h1_color", h1_color.name());
settings.setValue("h2_color", h2_color.name());
settings.setValue("h3_color", h3_color.name());
@ -196,6 +198,7 @@ bool DocumentStyle::load(QSettings &settings)
background_color = QColor(settings.value("background_color").toString());
standard_color = QColor(settings.value("standard_color").toString());
preformatted_color = QColor(settings.value("preformatted_color").toString());
blockquote_color = QColor(settings.value("blockquote_color").toString());
h1_color = QColor(settings.value("h1_color").toString());
h2_color = QColor(settings.value("h2_color").toString());
h3_color = QColor(settings.value("h3_color").toString());
@ -245,6 +248,8 @@ DocumentStyle DocumentStyle::derive(const QUrl &url) const
themed.internal_link_color = themed.external_link_color.lighter(110);
themed.cross_scheme_link_color = themed.external_link_color.darker(110);
themed.blockquote_color = themed.background_color.lighter(130);
break;
}
@ -261,6 +266,8 @@ DocumentStyle DocumentStyle::derive(const QUrl &url) const
themed.internal_link_color = themed.external_link_color.darker(110);
themed.cross_scheme_link_color = themed.external_link_color.lighter(110);
themed.blockquote_color = themed.background_color.darker(120);
break;
}

View File

@ -30,6 +30,7 @@ struct DocumentStyle
QColor h1_color;
QColor h2_color;
QColor h3_color;
QColor blockquote_color;
QColor internal_link_color;
QColor external_link_color;

View File

@ -29,9 +29,6 @@ std::unique_ptr<GeminiDocument> GeminiRenderer::render(
DocumentStyle const & themed_style,
DocumentOutlineModel &outline)
{
QTextOption no_wrap;
no_wrap.setWrapMode(QTextOption::NoWrap);
QTextCharFormat preformatted;
preformatted.setFont(themed_style.preformatted_font);
preformatted.setForeground(themed_style.preformatted_color);
@ -67,17 +64,25 @@ std::unique_ptr<GeminiDocument> GeminiRenderer::render(
std::unique_ptr<GeminiDocument> result = std::make_unique<GeminiDocument>();
result->setDocumentMargin(themed_style.margin);
result->background_color = themed_style.background_color;
result->setDefaultTextOption(no_wrap);
result->setIndentWidth(20);
bool emit_fancy_text = global_settings.value("text_decoration").toBool();
QTextCursor cursor{result.get()};
QTextBlockFormat non_list_format = cursor.blockFormat();
QTextBlockFormat standard_format = cursor.blockFormat();
QTextBlockFormat preformatted_format = standard_format;
preformatted_format.setNonBreakableLines(true);
QTextBlockFormat block_quote_format = standard_format;
block_quote_format.setIndent(1);
block_quote_format.setBackground(themed_style.blockquote_color);
bool verbatim = false;
QTextList *current_list = nullptr;
bool blockquote = false;
outline.beginBuild();
@ -94,18 +99,19 @@ std::unique_ptr<GeminiDocument> GeminiRenderer::render(
{
if (line.startsWith("```"))
{
cursor.setBlockFormat(standard_format);
verbatim = false;
}
else
{
cursor.block().layout()->setTextOption(no_wrap);
cursor.setBlockFormat(preformatted_format);
cursor.setCharFormat(preformatted);
cursor.insertText(line + "\n");
}
}
else
{
if (line.startsWith("*"))
if (line.startsWith("* "))
{
if (current_list == nullptr)
{
@ -127,11 +133,31 @@ std::unique_ptr<GeminiDocument> GeminiRenderer::render(
if (current_list != nullptr)
{
cursor.insertBlock();
cursor.setBlockFormat(non_list_format);
cursor.setBlockFormat(standard_format);
}
current_list = nullptr;
}
if(line.startsWith(">"))
{
if(not blockquote ) {
// cursor.insertBlock();
}
blockquote = true;
cursor.setBlockFormat(block_quote_format);
cursor.insertText(trim_whitespace(line.mid(1)) + "\n", standard);
continue;
}
else
{
if(blockquote) {
cursor.setBlockFormat(standard_format);
}
blockquote = false;
}
if (line.startsWith("###"))
{
auto heading = trim_whitespace(line.mid(3));
@ -234,6 +260,8 @@ std::unique_ptr<GeminiDocument> GeminiRenderer::render(
{
if(emit_fancy_text)
{
// TODO: Fix UTF-8 encoding here… Don't emit single characters but always spans!
bool rendering_bold = false;
bool rendering_underlined = false;

View File

@ -34,5 +34,8 @@
<file>icons/gopher/telnet.svg</file>
<file>icons/gopher/text.svg</file>
<file>icons/info.svg</file>
<file>about/help.gemini</file>
<file>about/easter-egg.gemini</file>
<file>icons/help-box.svg</file>
</qresource>
</RCC>

1
src/icons/help-box.svg Normal file
View File

@ -0,0 +1 @@
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24"><path d="M11,18H13V16H11V18M12,6A4,4 0 0,0 8,10H10A2,2 0 0,1 12,8A2,2 0 0,1 14,10C14,12 11,11.75 11,15H13C13,12.75 16,12.5 16,10A4,4 0 0,0 12,6M5,3H19A2,2 0 0,1 21,5V19A2,2 0 0,1 19,21H5A2,2 0 0,1 3,19V5A2,2 0 0,1 5,3Z" /></svg>

After

Width:  |  Height:  |  Size: 504 B

View File

@ -65,6 +65,11 @@ MainWindow::MainWindow(QApplication * app, QWidget *parent) :
}
});
{
QShortcut * sc = new QShortcut(QKeySequence("Ctrl+L"), this);
connect(sc, &QShortcut::activated, this, &MainWindow::on_focus_inputbar);
}
{
global_settings.beginGroup("Window State");
if(global_settings.contains("geometry")) {
@ -378,3 +383,16 @@ void MainWindow::on_tab_fileLoaded(qint64 fileSize, const QString &mime, int mse
}
}
}
void MainWindow::on_focus_inputbar()
{
BrowserTab * tab = qobject_cast<BrowserTab*>(this->ui->browser_tabs->currentWidget());
if(tab != nullptr) {
tab->focusUrlBar();
}
}
void MainWindow::on_actionHelp_triggered()
{
this->addNewTab(true, QUrl("about:help"));
}

View File

@ -75,6 +75,10 @@ private slots:
void on_tab_fileLoaded(qint64 fileSize, QString const & mime, int msec);
void on_focus_inputbar();
void on_actionHelp_triggered();
private:
void reloadTheme();

View File

@ -205,6 +205,8 @@
<property name="title">
<string>Help</string>
</property>
<addaction name="actionHelp"/>
<addaction name="separator"/>
<addaction name="actionAbout"/>
<addaction name="actionAbout_Qt"/>
</widget>
@ -349,6 +351,21 @@
<property name="text">
<string>Go to home</string>
</property>
<property name="shortcut">
<string>Ctrl+H</string>
</property>
</action>
<action name="actionHelp">
<property name="icon">
<iconset resource="icons.qrc">
<normaloff>:/icons/help-box.svg</normaloff>:/icons/help-box.svg</iconset>
</property>
<property name="text">
<string>Help</string>
</property>
<property name="shortcut">
<string>F1</string>
</property>
</action>
</widget>
<resources>

View File

@ -108,6 +108,10 @@ void SettingsDialog::setGeminiStyle(DocumentStyle const &style)
.arg(this->current_style.background_color.name())
.arg("#FF00FF"));
ui->quote_preview->setStyleSheet(COLOR_STYLE
.arg(this->current_style.blockquote_color.name())
.arg("#FF00FF"));
ui->link_local_preview->setStyleSheet(COLOR_STYLE
.arg(this->current_style.background_color.name())
.arg(this->current_style.internal_link_color.name()));
@ -184,6 +188,8 @@ Plain text document here.
=> rela-link Same-Site Link
=> //foreign.host/ Foreign Site Link
=> https://foreign.host/ Cross-Protocol Link
> Multi-lined
> block quotes
```
@ -309,6 +315,10 @@ void SettingsDialog::on_link_cross_change_color_clicked()
{
updateColor(current_style.cross_scheme_link_color);
}
void SettingsDialog::on_quote_change_color_clicked()
{
updateColor(current_style.blockquote_color);
}
void SettingsDialog::on_link_local_prefix_textChanged(const QString &text)
{

View File

@ -79,6 +79,8 @@ private slots:
void on_SettingsDialog_accepted();
void on_quote_change_color_clicked();
private:
void reloadStylePreview();

View File

@ -7,7 +7,7 @@
<x>0</x>
<y>0</y>
<width>850</width>
<height>540</height>
<height>650</height>
</rect>
</property>
<property name="windowTitle">
@ -17,7 +17,7 @@
<item>
<widget class="QTabWidget" name="tabWidget">
<property name="currentIndex">
<number>0</number>
<number>1</number>
</property>
<widget class="QWidget" name="generic">
<attribute name="title">
@ -591,24 +591,24 @@
</item>
</layout>
</item>
<item row="11" column="0">
<item row="12" column="0">
<widget class="QLabel" name="label_12">
<property name="text">
<string>Auto-Theme Generation</string>
</property>
</widget>
</item>
<item row="11" column="1">
<item row="12" column="1">
<widget class="QComboBox" name="auto_theme"/>
</item>
<item row="12" column="0">
<item row="13" column="0">
<widget class="QLabel" name="label_13">
<property name="text">
<string>Page Margin</string>
</property>
</widget>
</item>
<item row="12" column="1">
<item row="13" column="1">
<widget class="QDoubleSpinBox" name="page_margin">
<property name="suffix">
<string> px</string>
@ -621,7 +621,7 @@
</property>
</widget>
</item>
<item row="13" column="1">
<item row="14" column="1">
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QComboBox" name="presets"/>
@ -701,13 +701,42 @@
</item>
</layout>
</item>
<item row="13" column="0">
<item row="14" column="0">
<widget class="QLabel" name="label_17">
<property name="text">
<string>Presets</string>
</property>
</widget>
</item>
<item row="11" column="0">
<widget class="QLabel" name="label_21">
<property name="text">
<string>Block Quote Background</string>
</property>
</widget>
</item>
<item row="11" column="1">
<layout class="QHBoxLayout" name="horizontalLayout_6">
<item>
<widget class="QLabel" name="quote_preview">
<property name="text">
<string> </string>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="quote_change_color">
<property name="text">
<string>...</string>
</property>
<property name="icon">
<iconset resource="icons.qrc">
<normaloff>:/icons/palette.svg</normaloff>:/icons/palette.svg</iconset>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item>
<item>