Compare commits
No commits in common. "gui" and "main" have entirely different histories.
17
README.md
17
README.md
@ -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
|
||||||
|
|||||||
3
build.rs
3
build.rs
@ -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();
|
||||||
}
|
}
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 21 KiB After Width: | Height: | Size: 21 KiB |
@ -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
|
||||||
|
|||||||
@ -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")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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 })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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.
|
||||||
|
|||||||
@ -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 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1 +0,0 @@
|
|||||||
singleton Logger 1.0 Logger.qml
|
|
||||||
13
qml/main.qml
13
qml/main.qml
@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +0,0 @@
|
|||||||
<RCC>
|
|
||||||
<qresource prefix="/images">
|
|
||||||
<file alias="kilroy.png">images/kilroy-256.png</file>
|
|
||||||
</qresource>
|
|
||||||
</RCC>
|
|
||||||
@ -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};
|
||||||
|
|||||||
@ -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(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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))
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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};
|
||||||
|
|||||||
@ -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;
|
||||||
|
|||||||
@ -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};
|
||||||
|
|||||||
@ -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};
|
||||||
|
|||||||
@ -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;
|
||||||
|
|||||||
@ -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::{
|
||||||
|
|||||||
@ -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};
|
||||||
|
|||||||
@ -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;
|
||||||
|
|||||||
@ -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;
|
||||||
|
|||||||
@ -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,
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user