Compare commits

..

No commits in common. "gui" and "main" have entirely different histories.
gui ... main

26 changed files with 217 additions and 470 deletions

View File

@ -19,22 +19,6 @@ And of course, [Rust](https://www.rust-lang.org/tools/install).
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
``` ```
This project requires at least Qt 6.7. To check your Qt version
```bash
qmake6 -query QT_VERSION
```
Use the [Qt Installer](https://www.qt.io/development/download) to download and install the Qt version of your choice.
**You must set the QMAKE variable before building clide**. This should be a path to `qmake6` binary installed on your system.
The following export is the default installation path for Qt 6.7 on Ubuntu 24.04
```bash
export QMAKE=$HOME/Qt/6.7.3/gcc_64/bin/qmake6
export LD_LIBRARY_PATH=$HOME/Qt/6.7.3/gcc_64/lib
```
## Usage ## Usage
To install and run clide To install and run clide
@ -142,7 +126,6 @@ Some helpful links for reading up on QML if you're just getting started.
* [All QML Controls Types](https://doc.qt.io/qt-6/qtquick-controls-qmlmodule.html) * [All QML Controls Types](https://doc.qt.io/qt-6/qtquick-controls-qmlmodule.html)
* [KDAB CXX-Qt Book](https://kdab.github.io/cxx-qt/book/) * [KDAB CXX-Qt Book](https://kdab.github.io/cxx-qt/book/)
* [github.com/KDAB/cxx-qt](https://github.com/KDAB/cxx-qt) * [github.com/KDAB/cxx-qt](https://github.com/KDAB/cxx-qt)
* [QML and C++ Intergration](https://doc.qt.io/qt-6/qtqml-cppintegration-overview.html)
### Plugins ### Plugins

View File

@ -8,8 +8,6 @@ fn main() {
"qml/ClideProjectView.qml", "qml/ClideProjectView.qml",
"qml/ClideEditor.qml", "qml/ClideEditor.qml",
"qml/ClideMenuBar.qml", "qml/ClideMenuBar.qml",
"qml/ClideLogger.qml",
"qml/Logger/Logger.qml",
])) ]))
// Link Qt's Network library // Link Qt's Network library
// - Qt Core is always linked // - Qt Core is always linked
@ -20,7 +18,6 @@ fn main() {
.qt_module("Gui") .qt_module("Gui")
.qt_module("Svg") .qt_module("Svg")
.qt_module("Xml") .qt_module("Xml")
.qrc("./resources.qrc")
.files(["src/gui/colors.rs", "src/gui/filesystem.rs"]) .files(["src/gui/colors.rs", "src/gui/filesystem.rs"])
.build(); .build();
} }

View File

Before

Width:  |  Height:  |  Size: 21 KiB

After

Width:  |  Height:  |  Size: 21 KiB

View File

@ -1,6 +1,4 @@
// SPDX-FileCopyrightText: 2026, Shaun Reed <shaunrd0@gmail.com> // TODO: Header
//
// SPDX-License-Identifier: GNU General Public License v3.0 or later
import QtQuick import QtQuick
import QtQuick.Controls.Basic import QtQuick.Controls.Basic
@ -31,7 +29,7 @@ ApplicationWindow {
anchors.top: parent.top anchors.top: parent.top
anchors.margins: 20 anchors.margins: 20
source: "qrc:/images/kilroy.png" source: "../icons/kilroy-256.png"
sourceSize.width: 80 sourceSize.width: 80
sourceSize.height: 80 sourceSize.height: 80
fillMode: Image.PreserveAspectFit fillMode: Image.PreserveAspectFit

View File

@ -1,13 +1,8 @@
// SPDX-FileCopyrightText: 2026, Shaun Reed <shaunrd0@gmail.com>
//
// SPDX-License-Identifier: GNU General Public License v3.0 or later
import QtQuick import QtQuick
import QtQuick.Controls import QtQuick.Controls
import QtQuick.Layouts import QtQuick.Layouts
import clide.module 1.0 import clide.module 1.0
import Logger 1.0
SplitView { SplitView {
id: root id: root
@ -79,9 +74,6 @@ SplitView {
text: parent.index + 1 text: parent.index + 1
verticalAlignment: Text.AlignVCenter verticalAlignment: Text.AlignVCenter
width: parent.width - indicator.width width: parent.width - indicator.width
background: Rectangle {
color: RustColors.terminal_background
}
} }
// Draw edge along the right side of the line number. // Draw edge along the right side of the line number.
Rectangle { Rectangle {
@ -153,8 +145,19 @@ SplitView {
} }
} }
} }
ClideLogger { TextArea {
id: areaConsole id: areaConsole
height: 100
placeholderText: qsTr("Placeholder for bash terminal.")
placeholderTextColor: "white"
readOnly: true
wrapMode: TextArea.Wrap
background: Rectangle {
color: RustColors.editor_background
implicitHeight: 100
// border.color: control.enabled ? RustColors.active : RustColors.inactive
}
} }
// We use an inline component to customize the horizontal and vertical // We use an inline component to customize the horizontal and vertical
@ -200,11 +203,4 @@ SplitView {
} }
} }
} }
Component.onCompleted: {
// Show logging is working.
Logger.debug("Debug console ready")
Logger.warn("Warnings show up too")
}
} }

View File

@ -1,58 +0,0 @@
// SPDX-FileCopyrightText: 2026, Shaun Reed <shaunrd0@gmail.com>
//
// SPDX-License-Identifier: GNU General Public License v3.0 or later
import QtQuick
import QtQuick.Controls
import clide.module 1.0
import Logger 1.0
Item {
ListModel { id: model }
Rectangle {
anchors.fill: parent
color: "#111"
}
ListView {
id: listView
anchors.fill: parent
model: model
clip: true
function getLogColor(level) {
switch (level) {
case "INFO":
return RustColors.info_log
break;
case "DEBUG":
return RustColors.debug_log
break;
case "WARN":
return RustColors.warn_log
break;
case "ERROR":
return RustColors.error_log
break;
default:
return RustColors.info_log
break;
}
}
delegate: Text {
text: `[${level}] ${message}`
font.family: "monospace"
color: listView.getLogColor(level)
}
}
Connections {
target: Logger
function onLogged(level, message) {
model.append({ level, message })
}
}
}

View File

@ -1,23 +1,13 @@
// SPDX-FileCopyrightText: 2026, Shaun Reed <shaunrd0@gmail.com>
//
// SPDX-License-Identifier: GNU General Public License v3.0 or later
import QtQuick import QtQuick
import QtQuick.Controls import QtQuick.Controls
import clide.module 1.0 import clide.module 1.0
MenuBar { MenuBar {
// Background for this MenuBar.
background: Rectangle {
color: RustColors.menubar
border.color: RustColors.explorer_background
}
// Base settings for each Menu. // Base settings for each Menu.
component ClideMenu : Menu { component ClideMenu : Menu {
background: Rectangle { background: Rectangle {
color: RustColors.explorer_background color: RustColors.menubar
implicitWidth: 100 implicitWidth: 100
radius: 2 radius: 2
} }
@ -29,7 +19,7 @@ MenuBar {
background: Rectangle { background: Rectangle {
color: root.hovered ? RustColors.hovered : RustColors.unhovered color: root.hovered ? RustColors.hovered : RustColors.unhovered
radius: 1.0 radius: 2.5
} }
contentItem: IconLabel { contentItem: IconLabel {
color: "black" color: "black"
@ -38,6 +28,13 @@ MenuBar {
} }
} }
// Background for this MenuBar.
background: Rectangle {
color: RustColors.menubar
border.color: RustColors.menubar_border
}
// //
// File Menu // File Menu
Action { Action {
@ -78,7 +75,7 @@ MenuBar {
MenuSeparator { MenuSeparator {
background: Rectangle { background: Rectangle {
border.color: color border.color: color
color: RustColors.explorer_background color: RustColors.menubar_border
implicitHeight: 3 implicitHeight: 3
implicitWidth: 200 implicitWidth: 200
} }

View File

@ -1,13 +1,8 @@
// SPDX-FileCopyrightText: 2026, Shaun Reed <shaunrd0@gmail.com>
//
// SPDX-License-Identifier: GNU General Public License v3.0 or later
import QtQuick import QtQuick
import QtQuick.Controls import QtQuick.Controls
import QtQuick.Layouts import QtQuick.Layouts
import clide.module 1.0 import clide.module 1.0
import Logger 1.0
SplitView { SplitView {
id: root id: root
@ -44,58 +39,18 @@ SplitView {
SplitView.preferredWidth: 200 SplitView.preferredWidth: 200
SplitView.maximumWidth: 250 SplitView.maximumWidth: 250
ColumnLayout { StackLayout {
spacing: 2
// TODO: Make a ClideBreadCrumb element to support select parent paths as root
Rectangle {
width: navigationView.width
height: 25
color: RustColors.explorer_background
Text {
id: breadCrumb
anchors.fill: parent anchors.fill: parent
text: clideTreeView.rootDirectory
color: RustColors.explorer_text
elide: Text.ElideLeft
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
}
TapHandler {
acceptedButtons: Qt.RightButton
onSingleTapped: (eventPoint, button) => contextMenu.popup()
}
Menu {
id: contextMenu
Action {
text: qsTr("Reset root index")
onTriggered: {
Logger.log("Resetting root directory: " + clideTreeView.originalRootDirectory)
clideTreeView.rootDirectory = clideTreeView.originalRootDirectory
}
}
}
}
ClideTreeView { ClideTreeView {
id: clideTreeView id: clideTreeView
onFileClicked: path => clideEditor.filePath = path onFileClicked: path => root.projectDir = path
width: navigationView.width
height: navigationView.height
// Path to the directory opened in the file explorer. // Path to the directory opened in the file explorer.
originalRootDirectory: root.projectDir
rootDirectory: root.projectDir rootDirectory: root.projectDir
onRootDirectoryChanged: {
Logger.log(clideTreeView.rootDirectory)
breadCrumb.text = clideTreeView.rootDirectory
}
} }
} }
} }
ClideEditor { ClideEditor {
id: clideEditor
SplitView.fillWidth: true SplitView.fillWidth: true
// Provide a path to the file currently open in the text editor. // Provide a path to the file currently open in the text editor.

View File

@ -1,35 +1,38 @@
// SPDX-FileCopyrightText: 2026, Shaun Reed <shaunrd0@gmail.com>
//
// SPDX-License-Identifier: GNU General Public License v3.0 or later
import QtQuick import QtQuick
import QtQuick.Effects
import QtQuick.Controls import QtQuick.Controls
import QtQuick.Layouts
import clide.module 1.0 import clide.module 1.0
import Logger 1.0
TreeView { Rectangle {
id: fileSystemTreeView id: root
model: FileSystem color: RustColors.explorer_background
property int lastIndex: -1 required property string rootDirectory
required property string originalRootDirectory
property string rootDirectory
signal fileClicked(string filePath) signal fileClicked(string filePath)
rootIndex: FileSystem.setDirectory(fileSystemTreeView.rootDirectory) TreeView {
leftMargin: 5 id: fileSystemTreeView
anchors.margins: 15
property int lastIndex: -1
model: FileSystem
anchors.fill: parent
boundsBehavior: Flickable.StopAtBounds boundsBehavior: Flickable.StopAtBounds
boundsMovement: Flickable.StopAtBounds boundsMovement: Flickable.StopAtBounds
clip: true clip: true
Component.onCompleted: {
FileSystem.setDirectory(root.rootDirectory)
fileSystemTreeView.expandRecursively(0, -1)
}
// The delegate represents a single entry in the filesystem. // The delegate represents a single entry in the filesystem.
delegate: TreeViewDelegate { delegate: TreeViewDelegate {
id: treeDelegate id: treeDelegate
indentation: 12 indentation: 8
implicitWidth: fileSystemTreeView.width > 0 ? fileSystemTreeView.width : 250 implicitWidth: fileSystemTreeView.width > 0 ? fileSystemTreeView.width : 250
implicitHeight: 25 implicitHeight: 25
@ -85,29 +88,8 @@ TreeView {
} }
} }
MultiEffect {
id: iconOverlay
anchors.fill: directoryIcon
source: directoryIcon
colorization: 1.0
brightness: 1.0
colorizationColor: {
const isFile = !treeDelegate.hasChildren;
if (isFile)
return Qt.lighter(RustColors.explorer_folder, 2)
const isExpandedFolder = treeDelegate.expanded && treeDelegate.hasChildren;
if (isExpandedFolder)
return Qt.darker(RustColors.explorer_folder, 2)
else
return RustColors.explorer_folder
}
}
HoverHandler { HoverHandler {
id: hoverHandler id: hoverHandler
acceptedDevices: PointerDevice.Mouse
} }
TapHandler { TapHandler {
@ -116,12 +98,14 @@ TreeView {
switch (button) { switch (button) {
case Qt.LeftButton: case Qt.LeftButton:
fileSystemTreeView.toggleExpanded(treeDelegate.row) fileSystemTreeView.toggleExpanded(treeDelegate.row)
fileSystemTreeView.lastIndex = treeDelegate.index
// If this model item doesn't have children, it means it's // If this model item doesn't have children, it means it's
// representing a file. // representing a file.
if (!treeDelegate.hasChildren) if (!treeDelegate.hasChildren)
fileSystemTreeView.fileClicked(treeDelegate.filePath) root.fileClicked(treeDelegate.filePath)
break; break;
case Qt.RightButton: case Qt.RightButton:
if (treeDelegate.hasChildren)
contextMenu.popup(); contextMenu.popup();
break; break;
} }
@ -132,17 +116,15 @@ TreeView {
id: contextMenu id: contextMenu
Action { Action {
text: qsTr("Set as root index") text: qsTr("Set as root index")
enabled: treeDelegate.hasChildren
onTriggered: { onTriggered: {
Logger.debug("Setting new root directory: " + treeDelegate.filePath) console.log("Setting directory: " + treeDelegate.filePath)
fileSystemTreeView.rootDirectory = treeDelegate.filePath FileSystem.setDirectory(treeDelegate.filePath)
} }
} }
Action { Action {
text: qsTr("Reset root index") text: qsTr("Reset root index")
onTriggered: { onTriggered: {
Logger.log("Resetting root directory: " + fileSystemTreeView.originalRootDirectory) FileSystem.setDirectory("")
fileSystemTreeView.rootDirectory = fileSystemTreeView.originalRootDirectory
} }
} }
} }
@ -167,4 +149,5 @@ TreeView {
} }
} }
} }
}
} }

View File

@ -1,30 +0,0 @@
// SPDX-FileCopyrightText: 2026, Shaun Reed <shaunrd0@gmail.com>
//
// SPDX-License-Identifier: GNU General Public License v3.0 or later
pragma Singleton
import QtQuick
QtObject {
signal logged(string level, string message)
function log(msg) {
console.log(msg)
logged("INFO", msg)
}
function debug(msg) {
console.log(msg)
logged("DEBUG", msg)
}
function warn(msg) {
console.warn(msg)
logged("WARN", msg)
}
function error(msg) {
console.error(msg)
logged("ERROR", msg)
}
}

View File

@ -1 +0,0 @@
singleton Logger 1.0 Logger.qml

View File

@ -1,7 +1,3 @@
// SPDX-FileCopyrightText: 2026, Shaun Reed <shaunrd0@gmail.com>
//
// SPDX-License-Identifier: GNU General Public License v3.0 or later
import QtQuick import QtQuick
import QtQuick.Controls import QtQuick.Controls
import QtQuick.Layouts import QtQuick.Layouts
@ -19,7 +15,13 @@ ApplicationWindow {
required property string appContextPath required property string appContextPath
menuBar: ClideMenuBar { } menuBar: ClideMenuBar {
}
Rectangle {
anchors.fill: parent
color: RustColors.gutter
}
MessageDialog { MessageDialog {
id: errorDialog id: errorDialog
@ -27,7 +29,6 @@ ApplicationWindow {
title: qsTr("Error") title: qsTr("Error")
} }
ClideProjectView { ClideProjectView {
id: clideProjectView
projectDir: appWindow.appContextPath projectDir: appWindow.appContextPath
} }
} }

View File

@ -1,5 +0,0 @@
<RCC>
<qresource prefix="/images">
<file alias="kilroy.png">images/kilroy-256.png</file>
</qresource>
</RCC>

View File

@ -1,7 +1,3 @@
// SPDX-FileCopyrightText: 2026, Shaun Reed <shaunrd0@gmail.com>
//
// SPDX-License-Identifier: GNU General Public License v3.0 or later
use crate::AppContext; use crate::AppContext;
use anyhow::Result; use anyhow::Result;
use cxx_qt_lib::{QMapPair, QMapPair_QString_QVariant, QString, QVariant}; use cxx_qt_lib::{QMapPair, QMapPair_QString_QVariant, QString, QVariant};

View File

@ -1,9 +1,4 @@
// SPDX-FileCopyrightText: 2026, Shaun Reed <shaunrd0@gmail.com>
//
// SPDX-License-Identifier: GNU General Public License v3.0 or later
#[cxx_qt::bridge] #[cxx_qt::bridge]
pub mod qobject { pub mod qobject {
unsafe extern "C++" { unsafe extern "C++" {
include!("cxx-qt-lib/qcolor.h"); include!("cxx-qt-lib/qcolor.h");
@ -36,11 +31,6 @@ pub mod qobject {
#[qproperty(QColor, explorer_background)] #[qproperty(QColor, explorer_background)]
#[qproperty(QColor, explorer_folder)] #[qproperty(QColor, explorer_folder)]
#[qproperty(QColor, explorer_folder_open)] #[qproperty(QColor, explorer_folder_open)]
#[qproperty(QColor, terminal_background)]
#[qproperty(QColor, info_log)]
#[qproperty(QColor, debug_log)]
#[qproperty(QColor, warn_log)]
#[qproperty(QColor, error_log)]
type RustColors = super::RustColorsImpl; type RustColors = super::RustColorsImpl;
} }
} }
@ -70,11 +60,6 @@ pub struct RustColorsImpl {
explorer_background: QColor, explorer_background: QColor,
explorer_folder: QColor, explorer_folder: QColor,
explorer_folder_open: QColor, explorer_folder_open: QColor,
terminal_background: QColor,
info_log: QColor,
debug_log: QColor,
warn_log: QColor,
error_log: QColor,
} }
impl Default for RustColorsImpl { impl Default for RustColorsImpl {
@ -83,7 +68,7 @@ impl Default for RustColorsImpl {
hovered: QColor::try_from("#303234").unwrap(), hovered: QColor::try_from("#303234").unwrap(),
unhovered: QColor::try_from("#3c3f41").unwrap(), unhovered: QColor::try_from("#3c3f41").unwrap(),
pressed: QColor::try_from("#4b4f51").unwrap(), pressed: QColor::try_from("#4b4f51").unwrap(),
menubar: QColor::try_from("#262626").unwrap(), menubar: QColor::try_from("#3c3f41").unwrap(),
menubar_border: QColor::try_from("#575757").unwrap(), menubar_border: QColor::try_from("#575757").unwrap(),
scrollbar: QColor::try_from("#4b4f51").unwrap(), scrollbar: QColor::try_from("#4b4f51").unwrap(),
scrollbar_active: QColor::try_from("#4b4f51").unwrap(), scrollbar_active: QColor::try_from("#4b4f51").unwrap(),
@ -91,22 +76,17 @@ impl Default for RustColorsImpl {
linenumber: QColor::try_from("#94989b").unwrap(), linenumber: QColor::try_from("#94989b").unwrap(),
active: QColor::try_from("#a9acb0").unwrap(), active: QColor::try_from("#a9acb0").unwrap(),
inactive: QColor::try_from("#FFF").unwrap(), inactive: QColor::try_from("#FFF").unwrap(),
editor_background: QColor::try_from("#111111").unwrap(), editor_background: QColor::try_from("#2b2b2b").unwrap(),
editor_text: QColor::try_from("#acaea3").unwrap(), editor_text: QColor::try_from("#acaea3").unwrap(),
editor_highlighted_text: QColor::try_from("#ccced3").unwrap(), editor_highlighted_text: QColor::try_from("#ccced3").unwrap(),
editor_highlight: QColor::try_from("#ccced3").unwrap(), editor_highlight: QColor::try_from("#ccced3").unwrap(),
gutter: QColor::try_from("#1e1f22").unwrap(), gutter: QColor::try_from("#1e1f22").unwrap(),
explorer_hovered: QColor::try_from("#4c5053").unwrap(), explorer_hovered: QColor::try_from("#4c5053").unwrap(),
explorer_text: QColor::try_from("#FFF").unwrap(), explorer_text: QColor::try_from("#3b3b3b").unwrap(),
explorer_text_selected: QColor::try_from("#262626").unwrap(), explorer_text_selected: QColor::try_from("#8b8b8b").unwrap(),
explorer_background: QColor::try_from("#1E1F22").unwrap(), explorer_background: QColor::try_from("#676c70").unwrap(),
explorer_folder: QColor::try_from("#54585b").unwrap(), explorer_folder: QColor::try_from("#54585b").unwrap(),
explorer_folder_open: QColor::try_from("#2b2b2b").unwrap(), explorer_folder_open: QColor::try_from("#FFF").unwrap(),
terminal_background: QColor::try_from("#111111").unwrap(),
info_log: QColor::try_from("#C4FFFF").unwrap(),
debug_log: QColor::try_from("#55ff99").unwrap(),
warn_log: QColor::try_from("#ffaa00").unwrap(),
error_log: QColor::try_from("#ff5555").unwrap(),
} }
} }
} }

View File

@ -1,20 +1,3 @@
// SPDX-FileCopyrightText: 2026, Shaun Reed <shaunrd0@gmail.com>
//
// SPDX-License-Identifier: GNU General Public License v3.0 or later
use cxx_qt_lib::{QModelIndex, QString};
use dirs;
use log::warn;
use std::fs;
use std::path::Path;
use syntect::easy::HighlightLines;
use syntect::highlighting::ThemeSet;
use syntect::html::{
IncludeBackground, append_highlighted_html_for_styled_line, start_highlighted_html_snippet,
};
use syntect::parsing::SyntaxSet;
use syntect::util::LinesWithEndings;
#[cxx_qt::bridge] #[cxx_qt::bridge]
pub mod qobject { pub mod qobject {
unsafe extern "C++" { unsafe extern "C++" {
@ -34,6 +17,7 @@ pub mod qobject {
#[qml_element] #[qml_element]
#[qml_singleton] #[qml_singleton]
#[qproperty(QString, file_path, cxx_name = "filePath")] #[qproperty(QString, file_path, cxx_name = "filePath")]
#[qproperty(QModelIndex, root_index, cxx_name = "rootIndex")]
type FileSystem = super::FileSystemImpl; type FileSystem = super::FileSystemImpl;
#[inherit] #[inherit]
@ -55,9 +39,22 @@ pub mod qobject {
} }
} }
// TODO: Implement a provider for QFileSystemModel::setIconProvider for icons. use cxx_qt_lib::{QModelIndex, QString};
use dirs;
use log::warn;
use std::fs;
use std::io::BufRead;
use syntect::easy::HighlightFile;
use syntect::highlighting::ThemeSet;
use syntect::html::{
IncludeBackground, append_highlighted_html_for_styled_line, start_highlighted_html_snippet,
};
use syntect::parsing::SyntaxSet;
// TODO: Impleent a provider for QFileSystemModel::setIconProvider for icons.
pub struct FileSystemImpl { pub struct FileSystemImpl {
file_path: QString, file_path: QString,
root_index: QModelIndex,
} }
// Default is explicit to make the editor open this source file initially. // Default is explicit to make the editor open this source file initially.
@ -65,6 +62,7 @@ impl Default for FileSystemImpl {
fn default() -> Self { fn default() -> Self {
Self { Self {
file_path: QString::from(file!()), file_path: QString::from(file!()),
root_index: Default::default(),
} }
} }
} }
@ -74,31 +72,30 @@ impl qobject::FileSystem {
if path.is_empty() { if path.is_empty() {
return QString::default(); return QString::default();
} }
let meta = fs::metadata(path.to_string()) if !fs::metadata(path.to_string())
.expect(format!("Failed to get file metadata {path:?}").as_str()); .expect(format!("Failed to get file metadata {path:?}").as_str())
if !meta.is_file() { .is_file()
{
warn!(target:"FileSystem", "Attempted to open file {path:?} that is not a valid file"); warn!(target:"FileSystem", "Attempted to open file {path:?} that is not a valid file");
return QString::default(); return QString::default();
} }
let path_str = path.to_string();
if let Ok(lines) = fs::read_to_string(path_str.as_str()) {
let ss = SyntaxSet::load_defaults_nonewlines(); let ss = SyntaxSet::load_defaults_nonewlines();
let ts = ThemeSet::load_defaults(); let ts = ThemeSet::load_defaults();
let theme = &ts.themes["base16-ocean.dark"]; let theme = &ts.themes["base16-ocean.dark"];
let lang = ss
.find_syntax_by_extension( let mut highlighter =
Path::new(path_str.as_str()) HighlightFile::new(path.to_string(), &ss, theme).expect("Failed to create highlighter");
.extension()
.map(|s| s.to_str())
.unwrap_or_else(|| Some("md"))
.expect("Failed to get file extension"),
)
.unwrap_or_else(|| ss.find_syntax_plain_text());
let mut highlighter = HighlightLines::new(lang, theme);
let (mut output, _bg) = start_highlighted_html_snippet(theme); let (mut output, _bg) = start_highlighted_html_snippet(theme);
for line in LinesWithEndings::from(lines.as_str()) { let mut line = String::new();
while highlighter
.reader
.read_line(&mut line)
.expect("Failed to read file.")
> 0
{
let regions = highlighter let regions = highlighter
.highlight_line(line, &ss) .highlight_lines
.highlight_line(&line, &ss)
.expect("Failed to highlight"); .expect("Failed to highlight");
append_highlighted_html_for_styled_line( append_highlighted_html_for_styled_line(
@ -107,13 +104,10 @@ impl qobject::FileSystem {
&mut output, &mut output,
) )
.expect("Failed to insert highlighted html"); .expect("Failed to insert highlighted html");
line.clear();
} }
output.push_str("</pre>\n"); output.push_str("</pre>\n");
QString::from(output) QString::from(output)
} else {
return QString::default();
}
} }
// There will never be more than one column. // There will never be more than one column.
@ -130,13 +124,14 @@ impl qobject::FileSystem {
self.set_root_path(path) self.set_root_path(path)
} else { } else {
// If the initial directory can't be opened, attempt to find the home directory. // If the initial directory can't be opened, attempt to find the home directory.
let homedir = dirs::home_dir() self.set_root_path(&QString::from(
dirs::home_dir()
.expect("Failed to get home directory") .expect("Failed to get home directory")
.as_path() .as_path()
.to_str() .to_str()
.unwrap() .unwrap()
.to_string(); .to_string(),
self.set_root_path(&QString::from(homedir)) ))
} }
} }
} }

View File

@ -1,7 +1,3 @@
// SPDX-FileCopyrightText: 2026, Shaun Reed <shaunrd0@gmail.com>
//
// SPDX-License-Identifier: GNU General Public License v3.0 or later
use anyhow::{Context, Result, anyhow}; use anyhow::{Context, Result, anyhow};
use clap::Parser; use clap::Parser;
use log::{info, trace}; use log::{info, trace};

View File

@ -1,7 +1,3 @@
// SPDX-FileCopyrightText: 2026, Shaun Reed <shaunrd0@gmail.com>
//
// SPDX-License-Identifier: GNU General Public License v3.0 or later
mod about; mod about;
mod app; mod app;
mod component; mod component;

View File

@ -1,7 +1,3 @@
// SPDX-FileCopyrightText: 2026, Shaun Reed <shaunrd0@gmail.com>
//
// SPDX-License-Identifier: GNU General Public License v3.0 or later
use ratatui::buffer::Buffer; use ratatui::buffer::Buffer;
use ratatui::layout::{Constraint, Direction, Layout, Rect}; use ratatui::layout::{Constraint, Direction, Layout, Rect};
use ratatui::text::{Line, Span}; use ratatui::text::{Line, Span};

View File

@ -1,7 +1,3 @@
// SPDX-FileCopyrightText: 2026, Shaun Reed <shaunrd0@gmail.com>
//
// SPDX-License-Identifier: GNU General Public License v3.0 or later
use crate::tui::about::About; use crate::tui::about::About;
use crate::tui::app::AppComponent::{AppEditor, AppExplorer, AppLogger}; use crate::tui::app::AppComponent::{AppEditor, AppExplorer, AppLogger};
use crate::tui::component::{Action, Component, Focus, FocusState, Visibility, VisibleState}; use crate::tui::component::{Action, Component, Focus, FocusState, Visibility, VisibleState};

View File

@ -1,7 +1,3 @@
// SPDX-FileCopyrightText: 2026, Shaun Reed <shaunrd0@gmail.com>
//
// SPDX-License-Identifier: GNU General Public License v3.0 or later
#![allow(dead_code, unused_variables)] #![allow(dead_code, unused_variables)]
use crate::tui::component::Focus::Inactive; use crate::tui::component::Focus::Inactive;

View File

@ -1,7 +1,3 @@
// SPDX-FileCopyrightText: 2026, Shaun Reed <shaunrd0@gmail.com>
//
// SPDX-License-Identifier: GNU General Public License v3.0 or later
use crate::tui::component::{Action, Component, ComponentState, Focus, FocusState}; use crate::tui::component::{Action, Component, ComponentState, Focus, FocusState};
use anyhow::{Context, Result, bail}; use anyhow::{Context, Result, bail};
use edtui::{ use edtui::{

View File

@ -1,7 +1,3 @@
// SPDX-FileCopyrightText: 2026, Shaun Reed <shaunrd0@gmail.com>
//
// SPDX-License-Identifier: GNU General Public License v3.0 or later
use crate::tui::component::{Action, Component, Focus, FocusState}; use crate::tui::component::{Action, Component, Focus, FocusState};
use crate::tui::editor::Editor; use crate::tui::editor::Editor;
use anyhow::{Context, Result, anyhow}; use anyhow::{Context, Result, anyhow};

View File

@ -1,7 +1,3 @@
// SPDX-FileCopyrightText: 2026, Shaun Reed <shaunrd0@gmail.com>
//
// SPDX-License-Identifier: GNU General Public License v3.0 or later
use crate::tui::component::{Action, Component, ComponentState, Focus, FocusState}; use crate::tui::component::{Action, Component, ComponentState, Focus, FocusState};
use anyhow::{Context, Result, bail}; use anyhow::{Context, Result, bail};
use log::trace; use log::trace;

View File

@ -1,7 +1,3 @@
// SPDX-FileCopyrightText: 2026, Shaun Reed <shaunrd0@gmail.com>
//
// SPDX-License-Identifier: GNU General Public License v3.0 or later
use crate::tui::component::{Action, Component, ComponentState, Focus, FocusState}; use crate::tui::component::{Action, Component, ComponentState, Focus, FocusState};
use log::{LevelFilter, trace}; use log::{LevelFilter, trace};
use ratatui::buffer::Buffer; use ratatui::buffer::Buffer;

View File

@ -1,7 +1,3 @@
// SPDX-FileCopyrightText: 2026, Shaun Reed <shaunrd0@gmail.com>
//
// SPDX-License-Identifier: GNU General Public License v3.0 or later
use crate::tui::component::{Action, Component, ComponentState, FocusState}; use crate::tui::component::{Action, Component, ComponentState, FocusState};
use crate::tui::menu_bar::MenuBarItemOption::{ use crate::tui::menu_bar::MenuBarItemOption::{
About, CloseTab, Exit, Reload, Save, ShowHideExplorer, ShowHideLogger, About, CloseTab, Exit, Reload, Save, ShowHideExplorer, ShowHideLogger,