Compare commits
30 Commits
main
...
1b60947177
| Author | SHA1 | Date | |
|---|---|---|---|
| 1b60947177 | |||
| f918d65888 | |||
| aa42ec6072 | |||
| 6f2a655497 | |||
| c0f38b531d | |||
| 4aad91416e | |||
| ff1b5ab2e6 | |||
| 491087a6c1 | |||
| c170b3b20d | |||
| 125041f469 | |||
| 67bf82d0cb | |||
| 39377b32f0 | |||
| 176efb97b7 | |||
| 755066d847 | |||
| 773d7818b5 | |||
| 7e58e3ee03 | |||
| 0f50577d78 | |||
| 29024e3999 | |||
| 5af09485a3 | |||
| e5b91eaed8 | |||
| be383869b2 | |||
| b9eee50e52 | |||
| 4cc43916cb | |||
| a5bed9ed2c | |||
| 0fac2b71ab | |||
| db2f878018 | |||
| 048d40eb83 | |||
| c70bba16e4 | |||
| 325cf285fc | |||
| aa8590cd5c |
@@ -107,8 +107,6 @@ cargo run
|
|||||||
clide
|
clide
|
||||||
```
|
```
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
## Development
|
## Development
|
||||||
|
|
||||||
It's recommended to use RustRover or Qt Creator for development.
|
It's recommended to use RustRover or Qt Creator for development.
|
||||||
|
|||||||
27
build.rs
27
build.rs
@@ -2,21 +2,20 @@ use cxx_qt_build::{CxxQtBuilder, QmlModule};
|
|||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
CxxQtBuilder::new_qml_module(QmlModule::new("clide.module").qml_files(&[
|
CxxQtBuilder::new_qml_module(QmlModule::new("clide.module").qml_files(&[
|
||||||
"qml/ClideApplicationView.qml",
|
|
||||||
"qml/ClideEditorView.qml",
|
|
||||||
"qml/ClideExplorerView.qml",
|
|
||||||
"qml/ClideTreeView.qml",
|
|
||||||
"qml/Components/ClideAboutWindow.qml",
|
|
||||||
"qml/Components/ClideBreadCrumbs.qml",
|
|
||||||
"qml/Components/ClideEditor.qml",
|
|
||||||
"qml/Components/ClideHandle.qml",
|
|
||||||
"qml/Components/ClideLogger.qml",
|
|
||||||
"qml/Components/ClideMenu.qml",
|
|
||||||
"qml/Components/ClideMenuBar.qml",
|
|
||||||
"qml/Components/ClideMenuItem.qml",
|
|
||||||
"qml/Components/ClideScrollBar.qml",
|
|
||||||
"qml/Logger/Logger.qml",
|
|
||||||
"qml/main.qml",
|
"qml/main.qml",
|
||||||
|
"qml/ClideAboutWindow.qml",
|
||||||
|
"qml/ClideTreeView.qml",
|
||||||
|
"qml/ClideProjectView.qml",
|
||||||
|
"qml/ClideEditor.qml",
|
||||||
|
"qml/ClideEditorView.qml",
|
||||||
|
"qml/ClideMenuBar.qml",
|
||||||
|
"qml/ClideLogger.qml",
|
||||||
|
"qml/Components/ClideScrollBar.qml",
|
||||||
|
"qml/Components/ClideHandle.qml",
|
||||||
|
"qml/Components/ClideMenu.qml",
|
||||||
|
"qml/Components/ClideMenuItem.qml",
|
||||||
|
"qml/Components/ClideBreadCrumbs.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
|
||||||
|
|||||||
@@ -1,46 +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 QtQuick.Layouts
|
|
||||||
|
|
||||||
import clide.module 1.0
|
|
||||||
import Logger 1.0
|
|
||||||
|
|
||||||
SplitView {
|
|
||||||
id: root
|
|
||||||
|
|
||||||
// Path to the directory of the project opened in clide.
|
|
||||||
required property string projectDir
|
|
||||||
|
|
||||||
anchors.fill: parent
|
|
||||||
|
|
||||||
// Customized handle to drag between the Navigation and the Editor.
|
|
||||||
handle: ClideHandle {
|
|
||||||
hovered: SplitHandle.hovered
|
|
||||||
pressed: SplitHandle.pressed
|
|
||||||
}
|
|
||||||
|
|
||||||
ClideExplorerView {
|
|
||||||
SplitView.fillHeight: true
|
|
||||||
SplitView.preferredWidth: 200
|
|
||||||
projectDir: root.projectDir
|
|
||||||
|
|
||||||
// Open files when clicked in the explorer.
|
|
||||||
onFileClicked: path => {
|
|
||||||
Logger.trace("Setting editor path from ClideExplorerView signal: " + path)
|
|
||||||
clideEditorView.filePath = path;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ClideEditorView {
|
|
||||||
id: clideEditorView
|
|
||||||
|
|
||||||
SplitView.fillHeight: true
|
|
||||||
SplitView.fillWidth: true
|
|
||||||
// Provide a path to the file currently open in the text editor.
|
|
||||||
// Initialized using the Default trait in Rust QML singleton FileSystem.
|
|
||||||
filePath: FileSystem.filePath
|
|
||||||
}
|
|
||||||
}
|
|
||||||
136
qml/ClideEditor.qml
Normal file
136
qml/ClideEditor.qml
Normal file
@@ -0,0 +1,136 @@
|
|||||||
|
// 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 QtQuick.Layouts
|
||||||
|
|
||||||
|
import clide.module 1.0
|
||||||
|
import Logger 1.0
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
// We use a flickable to synchronize the position of the editor and
|
||||||
|
// the line numbers. This is necessary because the line numbers can
|
||||||
|
// extend the available height.
|
||||||
|
Flickable {
|
||||||
|
id: lineNumbers
|
||||||
|
|
||||||
|
Layout.fillHeight: true
|
||||||
|
Layout.fillWidth: false
|
||||||
|
// Calculating the width correctly is important as the number grows.
|
||||||
|
// We need to ensure space required to show N line number digits.
|
||||||
|
// We use log10 to find how many digits are needed in a line number.
|
||||||
|
// log10(9) ~= .95; log10(10) = 1.0; log10(100) = 2.0 ...etc
|
||||||
|
// We +1 to ensure space for at least 1 digit, as floor(1.95) = 1.
|
||||||
|
// The +10 is additional spacing and can be adjusted.
|
||||||
|
Layout.preferredWidth: fontMetrics.averageCharacterWidth * (Math.floor(Math.log10(textArea.lineCount)) + 1) + 10
|
||||||
|
contentY: editorFlickable.contentY
|
||||||
|
interactive: false
|
||||||
|
|
||||||
|
Column {
|
||||||
|
anchors.fill: parent
|
||||||
|
topPadding: textArea.topPadding
|
||||||
|
|
||||||
|
Repeater {
|
||||||
|
id: repeatedLineNumbers
|
||||||
|
|
||||||
|
// TODO: Bug where text wrapping shows as new line number.
|
||||||
|
model: textArea.lineCount
|
||||||
|
|
||||||
|
// This Item is used for each line number in the gutter.
|
||||||
|
delegate: Item {
|
||||||
|
required property int index
|
||||||
|
|
||||||
|
// Calculates the height of each line in the text area.
|
||||||
|
height: textArea.contentHeight / textArea.lineCount
|
||||||
|
width: parent.width
|
||||||
|
|
||||||
|
// Show the line number.
|
||||||
|
Label {
|
||||||
|
id: numbers
|
||||||
|
|
||||||
|
color: RustColors.linenumber
|
||||||
|
font: textArea.font
|
||||||
|
height: parent.height
|
||||||
|
horizontalAlignment: Text.AlignLeft
|
||||||
|
text: parent.index + 1
|
||||||
|
verticalAlignment: Text.AlignVCenter
|
||||||
|
width: parent.width - indicator.width
|
||||||
|
|
||||||
|
background: Rectangle {
|
||||||
|
color: RustColors.terminal_background
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Draw edge along the right side of the line number.
|
||||||
|
Rectangle {
|
||||||
|
id: indicator
|
||||||
|
|
||||||
|
anchors.left: numbers.right
|
||||||
|
color: RustColors.linenumber
|
||||||
|
height: parent.height
|
||||||
|
width: 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Flickable {
|
||||||
|
id: editorFlickable
|
||||||
|
|
||||||
|
Layout.fillHeight: true
|
||||||
|
Layout.fillWidth: true
|
||||||
|
boundsBehavior: Flickable.StopAtBounds
|
||||||
|
height: 650
|
||||||
|
|
||||||
|
ScrollBar.horizontal: ClideScrollBar {
|
||||||
|
}
|
||||||
|
ScrollBar.vertical: ClideScrollBar {
|
||||||
|
}
|
||||||
|
TextArea.flickable: TextArea {
|
||||||
|
id: textArea
|
||||||
|
|
||||||
|
antialiasing: true
|
||||||
|
focus: true
|
||||||
|
persistentSelection: true
|
||||||
|
selectByMouse: true
|
||||||
|
selectedTextColor: RustColors.editor_highlighted_text
|
||||||
|
selectionColor: RustColors.editor_highlight
|
||||||
|
text: FileSystem.readFile(root.filePath)
|
||||||
|
textFormat: Qt.AutoText
|
||||||
|
wrapMode: TextArea.Wrap
|
||||||
|
|
||||||
|
onLinkActivated: function (link) {
|
||||||
|
Qt.openUrlExternally(link);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Handle saving
|
||||||
|
// Component.onCompleted: {
|
||||||
|
// if (Qt.application.arguments.length === 2)
|
||||||
|
// textDocument.source = "file:" + Qt.application.arguments[1]
|
||||||
|
// else
|
||||||
|
// textDocument.source = "qrc:/texteditor.html"
|
||||||
|
// }
|
||||||
|
// textDocument.onStatusChanged: {
|
||||||
|
// // a message lookup table using computed properties:
|
||||||
|
// // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Object_initializer
|
||||||
|
// const statusMessages = {
|
||||||
|
// [ TextDocument.ReadError ]: qsTr("Failed to load “%1”"),
|
||||||
|
// [ TextDocument.WriteError ]: qsTr("Failed to save “%1”"),
|
||||||
|
// [ TextDocument.NonLocalFileError ]: qsTr("Not a local file: “%1”"),
|
||||||
|
// }
|
||||||
|
// const err = statusMessages[textDocument.status]
|
||||||
|
// if (err) {
|
||||||
|
// errorDialog.text = err.arg(textDocument.source)
|
||||||
|
// errorDialog.open()
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
FontMetrics {
|
||||||
|
id: fontMetrics
|
||||||
|
|
||||||
|
font: textArea.font
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -9,26 +9,22 @@ import QtQuick.Layouts
|
|||||||
import clide.module 1.0
|
import clide.module 1.0
|
||||||
import Logger 1.0
|
import Logger 1.0
|
||||||
|
|
||||||
Rectangle {
|
SplitView {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
// The path to the file to show in the text editor.
|
// The path to the file to show in the text editor.
|
||||||
// This is updated by a signal caught within ClideApplicationView.
|
// This is updated by a signal caught within ClideProjectView.
|
||||||
|
// Initialized by the Default trait for the Rust QML singleton FileSystem.
|
||||||
required property string filePath
|
required property string filePath
|
||||||
|
|
||||||
clip: true
|
Layout.fillHeight: true
|
||||||
color: "transparent"
|
Layout.fillWidth: true
|
||||||
radius: 20
|
|
||||||
|
|
||||||
SplitView {
|
|
||||||
anchors.fill: parent
|
|
||||||
orientation: Qt.Vertical
|
orientation: Qt.Vertical
|
||||||
spacing: 3
|
|
||||||
|
|
||||||
// Customized handle to drag between the Editor and the Console.
|
// Customized handle to drag between the Editor and the Console.
|
||||||
handle: ClideHandle {
|
handle: ClideHandle {
|
||||||
hovered: SplitHandle.hovered
|
|
||||||
pressed: SplitHandle.pressed
|
pressed: SplitHandle.pressed
|
||||||
|
hovered: SplitHandle.hovered
|
||||||
}
|
}
|
||||||
|
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
@@ -41,9 +37,10 @@ Rectangle {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ClideEditor{
|
ClideEditor{
|
||||||
SplitView.preferredHeight: 650
|
id: clideEditor
|
||||||
}
|
}
|
||||||
ClideLogger {
|
ClideLogger {
|
||||||
}
|
id: areaConsole
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,62 +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 QtQuick.Layouts
|
|
||||||
|
|
||||||
import clide.module 1.0
|
|
||||||
import Logger 1.0
|
|
||||||
|
|
||||||
Rectangle {
|
|
||||||
id: root
|
|
||||||
|
|
||||||
required property string projectDir
|
|
||||||
|
|
||||||
signal fileClicked(string path)
|
|
||||||
|
|
||||||
clip: true
|
|
||||||
color: RustColors.explorer_background
|
|
||||||
topLeftRadius: 10
|
|
||||||
|
|
||||||
ColumnLayout {
|
|
||||||
anchors.fill: parent
|
|
||||||
spacing: 5
|
|
||||||
|
|
||||||
ClideBreadCrumbs {
|
|
||||||
id: breadCrumb
|
|
||||||
|
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.leftMargin: 15
|
|
||||||
Layout.rightMargin: 15
|
|
||||||
Layout.topMargin: 10
|
|
||||||
path: clideTreeView.rootDirectory
|
|
||||||
|
|
||||||
onCrumbClicked: path => {
|
|
||||||
Logger.trace("Crumb clicked: " + path);
|
|
||||||
clideTreeView.rootDirectory = path;
|
|
||||||
}
|
|
||||||
onResetRoot: {
|
|
||||||
clideTreeView.rootDirectory = clideTreeView.originalRootDirectory;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ClideTreeView {
|
|
||||||
id: clideTreeView
|
|
||||||
|
|
||||||
Layout.fillHeight: true
|
|
||||||
Layout.fillWidth: true
|
|
||||||
|
|
||||||
// Path to the directory opened in the file explorer.
|
|
||||||
originalRootDirectory: root.projectDir
|
|
||||||
rootDirectory: root.projectDir
|
|
||||||
|
|
||||||
// Pass the signal to the parent component using another signal.
|
|
||||||
onFileClicked: path => root.fileClicked(path)
|
|
||||||
onRootDirectoryChanged: {
|
|
||||||
Logger.log("Setting root directory: " + clideTreeView.rootDirectory);
|
|
||||||
breadCrumb.path = clideTreeView.rootDirectory;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -8,14 +8,15 @@ import QtQuick.Controls
|
|||||||
import clide.module 1.0
|
import clide.module 1.0
|
||||||
import Logger 1.0
|
import Logger 1.0
|
||||||
|
|
||||||
Rectangle {
|
Item {
|
||||||
color: RustColors.terminal_background
|
|
||||||
radius: 10
|
|
||||||
|
|
||||||
ListModel {
|
ListModel {
|
||||||
id: model
|
id: model
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Rectangle {
|
||||||
|
anchors.fill: parent
|
||||||
|
color: "#111"
|
||||||
|
}
|
||||||
ListView {
|
ListView {
|
||||||
id: listView
|
id: listView
|
||||||
|
|
||||||
@@ -37,6 +38,7 @@ Rectangle {
|
|||||||
}
|
}
|
||||||
|
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
|
clip: true
|
||||||
model: model
|
model: model
|
||||||
|
|
||||||
delegate: Text {
|
delegate: Text {
|
||||||
91
qml/ClideProjectView.qml
Normal file
91
qml/ClideProjectView.qml
Normal file
@@ -0,0 +1,91 @@
|
|||||||
|
// 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 QtQuick.Layouts
|
||||||
|
|
||||||
|
import clide.module 1.0
|
||||||
|
import Logger 1.0
|
||||||
|
|
||||||
|
SplitView {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
// Path to the directory of the project opened in clide.
|
||||||
|
required property string projectDir
|
||||||
|
|
||||||
|
Layout.fillHeight: true
|
||||||
|
Layout.fillWidth: true
|
||||||
|
anchors.fill: parent
|
||||||
|
|
||||||
|
// Customized handle to drag between the Navigation and the Editor.
|
||||||
|
handle: Rectangle {
|
||||||
|
id: verticalSplitHandle
|
||||||
|
|
||||||
|
border.color: SplitHandle.pressed ? RustColors.pressed : SplitHandle.hovered ? RustColors.hovered : RustColors.gutter
|
||||||
|
color: SplitHandle.pressed ? RustColors.pressed : SplitHandle.hovered ? RustColors.hovered : RustColors.gutter
|
||||||
|
implicitWidth: 8
|
||||||
|
radius: 2.5
|
||||||
|
|
||||||
|
// Execute these behaviors when the color is changed.
|
||||||
|
Behavior on color {
|
||||||
|
ColorAnimation {
|
||||||
|
duration: 400
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: navigationView
|
||||||
|
|
||||||
|
SplitView.fillHeight: true
|
||||||
|
SplitView.maximumWidth: 250
|
||||||
|
SplitView.minimumWidth: 0
|
||||||
|
SplitView.preferredWidth: 200
|
||||||
|
color: RustColors.explorer_background
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
spacing: 2
|
||||||
|
|
||||||
|
ClideBreadCrumbs {
|
||||||
|
id: breadCrumb
|
||||||
|
|
||||||
|
Layout.bottomMargin: 5
|
||||||
|
Layout.leftMargin: 15
|
||||||
|
Layout.topMargin: 5
|
||||||
|
path: clideTreeView.rootDirectory
|
||||||
|
|
||||||
|
onCrumbClicked: path => {
|
||||||
|
Logger.trace("Crumb clicked: " + path);
|
||||||
|
clideTreeView.rootDirectory = path;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ClideTreeView {
|
||||||
|
id: clideTreeView
|
||||||
|
|
||||||
|
height: navigationView.height
|
||||||
|
|
||||||
|
// Path to the directory opened in the file explorer.
|
||||||
|
originalRootDirectory: root.projectDir
|
||||||
|
rootDirectory: root.projectDir
|
||||||
|
width: navigationView.width
|
||||||
|
|
||||||
|
onFileClicked: path => clideEditor.filePath = path
|
||||||
|
onRootDirectoryChanged: {
|
||||||
|
Logger.log("Setting root directory: " + clideTreeView.rootDirectory);
|
||||||
|
breadCrumb.path = clideTreeView.rootDirectory;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ClideEditorView {
|
||||||
|
id: clideEditor
|
||||||
|
|
||||||
|
SplitView.fillWidth: true
|
||||||
|
|
||||||
|
// Provide a path to the file currently open in the text editor.
|
||||||
|
// Initialized using the Default trait in Rust QML singleton FileSystem.
|
||||||
|
filePath: FileSystem.filePath
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -10,30 +10,38 @@ import clide.module 1.0
|
|||||||
import Logger 1.0
|
import Logger 1.0
|
||||||
|
|
||||||
TreeView {
|
TreeView {
|
||||||
id: root
|
id: fileSystemTreeView
|
||||||
|
|
||||||
property int lastIndex: -1
|
property int lastIndex: -1
|
||||||
required property string originalRootDirectory
|
required property string originalRootDirectory
|
||||||
property string rootDirectory
|
property string rootDirectory
|
||||||
property int rootIndent: 25
|
|
||||||
|
|
||||||
signal fileClicked(string filePath)
|
signal fileClicked(string filePath)
|
||||||
|
|
||||||
boundsBehavior: Flickable.StopAtBounds
|
boundsBehavior: Flickable.StopAtBounds
|
||||||
boundsMovement: Flickable.StopAtBounds
|
boundsMovement: Flickable.StopAtBounds
|
||||||
clip: true
|
clip: true
|
||||||
|
leftMargin: 25
|
||||||
// The model is implemented in filesystem.rs
|
|
||||||
model: FileSystem
|
model: FileSystem
|
||||||
// Set the root directory on the Rust model, returning the QModeIndex to use for the root of the tree view widget.
|
rootIndex: FileSystem.setDirectory(fileSystemTreeView.rootDirectory)
|
||||||
rootIndex: FileSystem.setDirectory(root.rootDirectory)
|
|
||||||
|
|
||||||
// Provide our own custom ScrollIndicator for the TreeView.
|
// Provide our own custom ScrollIndicator for the TreeView.
|
||||||
ScrollBar.horizontal: ClideScrollBar {
|
ScrollIndicator.vertical: ScrollIndicator {
|
||||||
sizeModifier: 3
|
active: true
|
||||||
|
implicitWidth: 15
|
||||||
|
|
||||||
|
contentItem: Rectangle {
|
||||||
|
color: RustColors.scrollbar
|
||||||
|
implicitHeight: 6
|
||||||
|
implicitWidth: 6
|
||||||
|
opacity: fileSystemTreeView.movingVertically ? 0.5 : 0.0
|
||||||
|
|
||||||
|
Behavior on opacity {
|
||||||
|
OpacityAnimator {
|
||||||
|
duration: 500
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
ScrollBar.vertical: ClideScrollBar {
|
|
||||||
sizeModifier: 3
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// The delegate represents a single entry in the filesystem.
|
// The delegate represents a single entry in the filesystem.
|
||||||
@@ -45,40 +53,38 @@ TreeView {
|
|||||||
required property int index
|
required property int index
|
||||||
|
|
||||||
implicitHeight: 25
|
implicitHeight: 25
|
||||||
implicitWidth: root.width
|
implicitWidth: fileSystemTreeView.width > 0 ? fileSystemTreeView.width : 250
|
||||||
indentation: 12
|
indentation: 12
|
||||||
|
|
||||||
background: Rectangle {
|
background: Rectangle {
|
||||||
color: current ? RustColors.explorer_folder_open : "transparent"
|
color: current ? RustColors.explorer_folder_open : "transparent"
|
||||||
radius: 20
|
radius: 2.5
|
||||||
width: root.width
|
|
||||||
}
|
}
|
||||||
// Item name.
|
|
||||||
contentItem: Text {
|
contentItem: Text {
|
||||||
anchors.left: itemIcon.right
|
anchors.left: directoryIcon.right
|
||||||
anchors.leftMargin: 5
|
anchors.leftMargin: 5
|
||||||
color: RustColors.explorer_text
|
color: RustColors.explorer_text
|
||||||
text: treeDelegate.fileName
|
text: treeDelegate.fileName
|
||||||
}
|
}
|
||||||
// Item Icon.
|
|
||||||
indicator: Label {
|
indicator: Label {
|
||||||
id: itemIcon
|
id: directoryIcon
|
||||||
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
antialiasing: true
|
antialiasing: true
|
||||||
enabled: false
|
|
||||||
focus: false
|
|
||||||
font.family: localFont.font.family
|
font.family: localFont.font.family
|
||||||
font.pixelSize: 18
|
font.pixelSize: 18
|
||||||
smooth: true
|
smooth: true
|
||||||
// Get the icon from Rust implementation.
|
text: fileSystemTreeView.model.icon(filePath)
|
||||||
text: root.model.icon(filePath)
|
x: treeDelegate.leftMargin + (treeDelegate.depth * treeDelegate.indentation) + (indicator.visible ? indicator.width : 0)
|
||||||
x: root.rootIndent + (treeDelegate.depth * treeDelegate.indentation) + (carrotIndicator.visible ? carrotIndicator.width : 0)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Directory carrot indicator.
|
FontLoader {
|
||||||
|
id: localFont
|
||||||
|
|
||||||
|
source: "qrc:/fonts/saucecodepro-xlight.ttf"
|
||||||
|
}
|
||||||
Label {
|
Label {
|
||||||
id: carrotIndicator
|
id: indicator
|
||||||
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
font.family: localFont.font.family
|
font.family: localFont.font.family
|
||||||
@@ -86,11 +92,12 @@ TreeView {
|
|||||||
font.weight: localFont.font.weight
|
font.weight: localFont.font.weight
|
||||||
text: expanded ? "⮟" : "⮞"
|
text: expanded ? "⮟" : "⮞"
|
||||||
visible: isTreeNode && hasChildren
|
visible: isTreeNode && hasChildren
|
||||||
x: (root.rootIndent - implicitWidth) + (depth * indentation)
|
x: padding + (depth * indentation)
|
||||||
}
|
}
|
||||||
// Apply colorization effects to the icon for the item.
|
|
||||||
MultiEffect {
|
MultiEffect {
|
||||||
anchors.fill: itemIcon
|
id: iconOverlay
|
||||||
|
|
||||||
|
anchors.fill: directoryIcon
|
||||||
brightness: 1.0
|
brightness: 1.0
|
||||||
colorization: 1.0
|
colorization: 1.0
|
||||||
colorizationColor: {
|
colorizationColor: {
|
||||||
@@ -103,7 +110,7 @@ TreeView {
|
|||||||
else
|
else
|
||||||
return RustColors.explorer_folder;
|
return RustColors.explorer_folder;
|
||||||
}
|
}
|
||||||
source: itemIcon
|
source: directoryIcon
|
||||||
}
|
}
|
||||||
HoverHandler {
|
HoverHandler {
|
||||||
id: hoverHandler
|
id: hoverHandler
|
||||||
@@ -117,10 +124,10 @@ TreeView {
|
|||||||
switch (button) {
|
switch (button) {
|
||||||
case Qt.LeftButton:
|
case Qt.LeftButton:
|
||||||
if (treeDelegate.hasChildren) {
|
if (treeDelegate.hasChildren) {
|
||||||
root.toggleExpanded(treeDelegate.row);
|
fileSystemTreeView.toggleExpanded(treeDelegate.row);
|
||||||
} else {
|
} else {
|
||||||
// If this model item doesn't have children, it means it's representing a file.
|
// If this model item doesn't have children, it means it's representing a file.
|
||||||
root.fileClicked(treeDelegate.filePath);
|
fileSystemTreeView.fileClicked(treeDelegate.filePath);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case Qt.RightButton:
|
case Qt.RightButton:
|
||||||
@@ -139,7 +146,7 @@ TreeView {
|
|||||||
|
|
||||||
onTriggered: {
|
onTriggered: {
|
||||||
Logger.debug("Setting new root directory: " + treeDelegate.filePath);
|
Logger.debug("Setting new root directory: " + treeDelegate.filePath);
|
||||||
root.rootDirectory = treeDelegate.filePath;
|
fileSystemTreeView.rootDirectory = treeDelegate.filePath;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -148,8 +155,8 @@ TreeView {
|
|||||||
text: qsTr("Reset root")
|
text: qsTr("Reset root")
|
||||||
|
|
||||||
onTriggered: {
|
onTriggered: {
|
||||||
Logger.log("Resetting root directory: " + root.originalRootDirectory);
|
Logger.log("Resetting root directory: " + fileSystemTreeView.originalRootDirectory);
|
||||||
root.rootDirectory = root.originalRootDirectory;
|
fileSystemTreeView.rootDirectory = fileSystemTreeView.originalRootDirectory;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -157,10 +164,4 @@ TreeView {
|
|||||||
}
|
}
|
||||||
selectionModel: ItemSelectionModel {
|
selectionModel: ItemSelectionModel {
|
||||||
}
|
}
|
||||||
|
|
||||||
FontLoader {
|
|
||||||
id: localFont
|
|
||||||
|
|
||||||
source: "qrc:/fonts/saucecodepro-xlight.ttf"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import QtQuick.Layouts 1.15
|
|||||||
import clide.module 1.0
|
import clide.module 1.0
|
||||||
import Logger 1.0
|
import Logger 1.0
|
||||||
|
|
||||||
Rectangle {
|
Item {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
property var fullPaths: []
|
property var fullPaths: []
|
||||||
@@ -13,30 +13,36 @@ Rectangle {
|
|||||||
property var segments: []
|
property var segments: []
|
||||||
|
|
||||||
signal crumbClicked(string path)
|
signal crumbClicked(string path)
|
||||||
signal resetRoot
|
|
||||||
|
|
||||||
function rebuildSegments(): string {
|
function rebuildSegments() {
|
||||||
let cleaned = path;
|
var cleaned = path;
|
||||||
if (cleaned.endsWith("/"))
|
if (cleaned.endsWith("/"))
|
||||||
cleaned = cleaned.slice(0, -1);
|
cleaned = cleaned.slice(0, -1);
|
||||||
|
var parts = cleaned.split("/");
|
||||||
|
root.segments = [];
|
||||||
|
root.fullPaths = [];
|
||||||
|
var current = "";
|
||||||
Logger.trace("Building segments for path: " + cleaned);
|
Logger.trace("Building segments for path: " + cleaned);
|
||||||
segments = ["/"];
|
for (var i = 0; i < parts.length; ++i) {
|
||||||
fullPaths = ["/"];
|
if (parts[i] === "") {
|
||||||
let parts = cleaned.split("/");
|
current = "/";
|
||||||
let current = "";
|
root.segments.push("/");
|
||||||
// We already pushed the root `/` path during initialization, so skip index 0.
|
root.fullPaths.push("/");
|
||||||
for (let i = 1; i < parts.length; ++i) {
|
} else {
|
||||||
|
if (current === "/")
|
||||||
|
current += parts[i];
|
||||||
|
else
|
||||||
current += "/" + parts[i];
|
current += "/" + parts[i];
|
||||||
Logger.trace("Pushing path: " + parts[i] + " Current: " + current);
|
Logger.trace("Pushing path: " + parts[i] + " Current: " + current);
|
||||||
segments.push(parts[i]);
|
root.segments.push(parts[i]);
|
||||||
fullPaths.push(current);
|
root.fullPaths.push(current);
|
||||||
}
|
}
|
||||||
// Update the model used in the Repeater to show the new segments.
|
}
|
||||||
repeater.model = segments;
|
rep.model = root.segments;
|
||||||
}
|
}
|
||||||
|
|
||||||
color: "transparent"
|
anchors.leftMargin: 20
|
||||||
implicitHeight: breadcrumbRow.implicitHeight
|
height: breadcrumbRow.implicitHeight
|
||||||
width: parent.width
|
width: parent.width
|
||||||
|
|
||||||
Component.onCompleted: rebuildSegments()
|
Component.onCompleted: rebuildSegments()
|
||||||
@@ -45,32 +51,28 @@ Rectangle {
|
|||||||
Flow {
|
Flow {
|
||||||
id: breadcrumbRow
|
id: breadcrumbRow
|
||||||
|
|
||||||
anchors.fill: parent
|
|
||||||
spacing: 2
|
|
||||||
width: parent.width
|
|
||||||
|
|
||||||
Repeater {
|
Repeater {
|
||||||
id: repeater
|
id: rep
|
||||||
|
|
||||||
model: root.segments
|
model: root.segments
|
||||||
|
|
||||||
delegate: Text {
|
delegate: Text {
|
||||||
required property int index
|
id: linkText
|
||||||
|
|
||||||
required property string modelData
|
required property string modelData
|
||||||
|
|
||||||
function getText(): string {
|
function getText() {
|
||||||
if (modelData === "/") {
|
if (modelData === "/") {
|
||||||
return modelData;
|
return modelData;
|
||||||
}
|
}
|
||||||
|
Logger.trace("Getting valid text:" + modelData);
|
||||||
return modelData + "/";
|
return modelData + "/";
|
||||||
}
|
}
|
||||||
|
|
||||||
// Show blue underlined hyperlink text if the mouse is hovering a segment.
|
|
||||||
color: mouseArea.containsMouse ? "#2a7fff" : RustColors.explorer_text
|
color: mouseArea.containsMouse ? "#2a7fff" : RustColors.explorer_text
|
||||||
font.underline: mouseArea.containsMouse
|
font.underline: mouseArea.containsMouse
|
||||||
text: getText()
|
text: getText()
|
||||||
|
|
||||||
// Click events for each path segment call signal so the parent can set the file explorer root path.
|
|
||||||
MouseArea {
|
MouseArea {
|
||||||
id: mouseArea
|
id: mouseArea
|
||||||
|
|
||||||
@@ -78,8 +80,8 @@ Rectangle {
|
|||||||
hoverEnabled: true
|
hoverEnabled: true
|
||||||
|
|
||||||
onClicked: {
|
onClicked: {
|
||||||
Logger.info(index + "] Breadcrumb clicked:" + root.fullPaths[index]);
|
console.log("Breadcrumb clicked:", root.fullPaths[root.segments.indexOf(modelData)]);
|
||||||
crumbClicked(root.fullPaths[index]);
|
root.crumbClicked(root.fullPaths[root.segments.indexOf(modelData)]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -88,7 +90,7 @@ Rectangle {
|
|||||||
TapHandler {
|
TapHandler {
|
||||||
acceptedButtons: Qt.RightButton
|
acceptedButtons: Qt.RightButton
|
||||||
|
|
||||||
onSingleTapped: contextMenu.popup()
|
onSingleTapped: (eventPoint, button) => contextMenu.popup()
|
||||||
}
|
}
|
||||||
ClideMenu {
|
ClideMenu {
|
||||||
id: contextMenu
|
id: contextMenu
|
||||||
@@ -98,8 +100,8 @@ Rectangle {
|
|||||||
text: qsTr("Reset root")
|
text: qsTr("Reset root")
|
||||||
|
|
||||||
onTriggered: {
|
onTriggered: {
|
||||||
Logger.info("Resetting root directory from ClideBreadCrumbs");
|
Logger.log("Resetting root directory: " + clideTreeView.originalRootDirectory);
|
||||||
resetRoot();
|
clideTreeView.rootDirectory = clideTreeView.originalRootDirectory;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,116 +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 QtQuick.Layouts
|
|
||||||
|
|
||||||
import clide.module 1.0
|
|
||||||
import Logger 1.0
|
|
||||||
|
|
||||||
Rectangle {
|
|
||||||
color: RustColors.editor_background
|
|
||||||
|
|
||||||
RowLayout {
|
|
||||||
anchors.fill: parent
|
|
||||||
|
|
||||||
// We use a flickable to synchronize the position of the editor and
|
|
||||||
// the line numbers. This is necessary because the line numbers can
|
|
||||||
// extend the available height.
|
|
||||||
Flickable {
|
|
||||||
id: lineNumbers
|
|
||||||
|
|
||||||
Layout.fillHeight: true
|
|
||||||
Layout.fillWidth: false
|
|
||||||
// Calculating the width correctly is important as the number grows.
|
|
||||||
// We need to ensure space required to show N line number digits.
|
|
||||||
// We use log10 to find how many digits are needed in a line number.
|
|
||||||
// log10(9) ~= .95; log10(10) = 1.0; log10(100) = 2.0 ...etc
|
|
||||||
// We +1 to ensure space for at least 1 digit, as floor(1.95) = 1.
|
|
||||||
// The +10 is additional spacing and can be adjusted.
|
|
||||||
Layout.preferredWidth: fontMetrics.averageCharacterWidth * (Math.floor(Math.log10(textArea.lineCount)) + 1) + 10
|
|
||||||
contentY: editorFlickable.contentY
|
|
||||||
interactive: false
|
|
||||||
|
|
||||||
Column {
|
|
||||||
anchors.fill: parent
|
|
||||||
topPadding: textArea.topPadding
|
|
||||||
|
|
||||||
Repeater {
|
|
||||||
id: repeatedLineNumbers
|
|
||||||
|
|
||||||
// TODO: Bug where text wrapping shows as new line number.
|
|
||||||
model: textArea.lineCount
|
|
||||||
|
|
||||||
// This Item is used for each line number in the gutter.
|
|
||||||
delegate: Item {
|
|
||||||
required property int index
|
|
||||||
|
|
||||||
// Calculates the height of each line in the text area.
|
|
||||||
height: textArea.contentHeight / textArea.lineCount
|
|
||||||
width: parent.width
|
|
||||||
|
|
||||||
// Show the line number.
|
|
||||||
Label {
|
|
||||||
id: numbers
|
|
||||||
|
|
||||||
color: RustColors.linenumber
|
|
||||||
font: textArea.font
|
|
||||||
height: parent.height
|
|
||||||
horizontalAlignment: Text.AlignLeft
|
|
||||||
text: parent.index + 1
|
|
||||||
verticalAlignment: Text.AlignVCenter
|
|
||||||
width: parent.width - indicator.width
|
|
||||||
}
|
|
||||||
// Draw an edge along the right side of the line number.
|
|
||||||
Rectangle {
|
|
||||||
id: indicator
|
|
||||||
|
|
||||||
anchors.left: numbers.right
|
|
||||||
color: RustColors.linenumber
|
|
||||||
height: parent.height
|
|
||||||
width: 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Flickable {
|
|
||||||
id: editorFlickable
|
|
||||||
|
|
||||||
Layout.fillHeight: true
|
|
||||||
Layout.fillWidth: true
|
|
||||||
boundsBehavior: Flickable.StopAtBounds
|
|
||||||
height: 650
|
|
||||||
|
|
||||||
ScrollBar.horizontal: ClideScrollBar {
|
|
||||||
}
|
|
||||||
ScrollBar.vertical: ClideScrollBar {
|
|
||||||
}
|
|
||||||
TextArea.flickable: TextArea {
|
|
||||||
id: textArea
|
|
||||||
|
|
||||||
antialiasing: true
|
|
||||||
focus: true
|
|
||||||
persistentSelection: true
|
|
||||||
selectByMouse: true
|
|
||||||
selectedTextColor: RustColors.editor_highlighted_text
|
|
||||||
selectionColor: RustColors.editor_highlight
|
|
||||||
text: FileSystem.readFile(root.filePath)
|
|
||||||
textFormat: Qt.AutoText
|
|
||||||
wrapMode: TextArea.Wrap
|
|
||||||
|
|
||||||
onLinkActivated: function (link) {
|
|
||||||
Qt.openUrlExternally(link);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
FontMetrics {
|
|
||||||
id: fontMetrics
|
|
||||||
|
|
||||||
font: textArea.font
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -16,7 +16,7 @@ Rectangle {
|
|||||||
} else if (hovered) {
|
} else if (hovered) {
|
||||||
return RustColors.hovered;
|
return RustColors.hovered;
|
||||||
} else {
|
} else {
|
||||||
return "transparent";
|
return RustColors.gutter;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
required property bool hovered
|
required property bool hovered
|
||||||
@@ -25,7 +25,6 @@ Rectangle {
|
|||||||
border.color: currentColor
|
border.color: currentColor
|
||||||
color: currentColor
|
color: currentColor
|
||||||
implicitHeight: 8
|
implicitHeight: 8
|
||||||
implicitWidth: 8
|
|
||||||
radius: 2.5
|
radius: 2.5
|
||||||
opacity: root.hovered ? 1.0 : 0.0
|
opacity: root.hovered ? 1.0 : 0.0
|
||||||
|
|
||||||
|
|||||||
@@ -11,10 +11,9 @@ ScrollBar {
|
|||||||
id: scrollBar
|
id: scrollBar
|
||||||
|
|
||||||
// Height, opacitiy, width
|
// Height, opacitiy, width
|
||||||
property int h: scrollBar.interactive ? sizeModifier * 2 : sizeModifier
|
property int h: scrollBar.interactive ? 4 * 2 : 4
|
||||||
property int o: scrollBar.active && scrollBar.size < 1.0 ? 1.0 : 0.0
|
property int o: scrollBar.active && scrollBar.size < 1.0 ? 1.0 : 0.0
|
||||||
property int sizeModifier: 4
|
property int w: scrollBar.interactive ? 4 * 2 : 4
|
||||||
property int w: scrollBar.interactive ? sizeModifier * 2 : sizeModifier
|
|
||||||
|
|
||||||
// Scroll bar gutter
|
// Scroll bar gutter
|
||||||
background: Rectangle {
|
background: Rectangle {
|
||||||
@@ -26,7 +25,6 @@ ScrollBar {
|
|||||||
|
|
||||||
// Fade the scrollbar gutter when inactive.
|
// Fade the scrollbar gutter when inactive.
|
||||||
opacity: scrollBar.o
|
opacity: scrollBar.o
|
||||||
radius: 20
|
|
||||||
|
|
||||||
Behavior on opacity {
|
Behavior on opacity {
|
||||||
OpacityAnimator {
|
OpacityAnimator {
|
||||||
@@ -57,7 +55,6 @@ ScrollBar {
|
|||||||
|
|
||||||
// Fade the scrollbar when inactive.
|
// Fade the scrollbar when inactive.
|
||||||
opacity: scrollBar.o
|
opacity: scrollBar.o
|
||||||
radius: 20
|
|
||||||
|
|
||||||
// Smooth transition between color changes based on the state above.
|
// Smooth transition between color changes based on the state above.
|
||||||
Behavior on color {
|
Behavior on color {
|
||||||
|
|||||||
@@ -3,7 +3,3 @@ ClideHandle ClideHandle.qml
|
|||||||
ClideMenu ClideMenu.qml
|
ClideMenu ClideMenu.qml
|
||||||
ClideMenuItem ClideMenuItem.qml
|
ClideMenuItem ClideMenuItem.qml
|
||||||
ClideBreadCrumbs ClideBreadCrumbs.qml
|
ClideBreadCrumbs ClideBreadCrumbs.qml
|
||||||
ClideAboutWindow ClideAboutWindow.qml
|
|
||||||
ClideEditor ClideEditor.qml
|
|
||||||
ClideLogger ClideLogger.qml
|
|
||||||
ClideMenuBar ClideMenuBar.qml
|
|
||||||
|
|||||||
23
qml/main.qml
23
qml/main.qml
@@ -15,29 +15,22 @@ ApplicationWindow {
|
|||||||
required property string appContextPath
|
required property string appContextPath
|
||||||
|
|
||||||
height: 800
|
height: 800
|
||||||
title: "Clide"
|
title: "CLIDE"
|
||||||
visible: true
|
visible: true
|
||||||
width: 1200
|
width: 1200
|
||||||
|
|
||||||
menuBar: ClideMenuBar {
|
menuBar: ClideMenuBar {
|
||||||
}
|
}
|
||||||
|
|
||||||
Rectangle {
|
MessageDialog {
|
||||||
color: RustColors.menubar
|
id: errorDialog
|
||||||
width: appView.implicitWidth
|
|
||||||
height: appView.implicitHeight
|
title: qsTr("Error")
|
||||||
|
}
|
||||||
|
ClideProjectView {
|
||||||
|
id: clideProjectView
|
||||||
|
|
||||||
ClideApplicationView {
|
|
||||||
id: appView
|
|
||||||
projectDir: appWindow.appContextPath
|
projectDir: appWindow.appContextPath
|
||||||
implicitHeight: appWindow.height
|
|
||||||
implicitWidth: appWindow.width
|
|
||||||
|
|
||||||
anchors.right: parent.right
|
|
||||||
anchors.bottom: parent.bottom
|
|
||||||
anchors.leftMargin: 20
|
|
||||||
anchors.topMargin: 10
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 402 KiB |
@@ -93,7 +93,7 @@ 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("#1E1F22").unwrap(),
|
editor_background: QColor::try_from("#111111").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(),
|
||||||
|
|||||||
@@ -10,7 +10,9 @@ use std::fs;
|
|||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use syntect::easy::HighlightLines;
|
use syntect::easy::HighlightLines;
|
||||||
use syntect::highlighting::ThemeSet;
|
use syntect::highlighting::ThemeSet;
|
||||||
use syntect::html::{IncludeBackground, append_highlighted_html_for_styled_line};
|
use syntect::html::{
|
||||||
|
IncludeBackground, append_highlighted_html_for_styled_line, start_highlighted_html_snippet,
|
||||||
|
};
|
||||||
use syntect::parsing::SyntaxSet;
|
use syntect::parsing::SyntaxSet;
|
||||||
use syntect::util::LinesWithEndings;
|
use syntect::util::LinesWithEndings;
|
||||||
|
|
||||||
@@ -57,6 +59,7 @@ pub mod qobject {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Implement a provider for QFileSystemModel::setIconProvider for icons.
|
||||||
pub struct FileSystemImpl {
|
pub struct FileSystemImpl {
|
||||||
file_path: QString,
|
file_path: QString,
|
||||||
}
|
}
|
||||||
@@ -96,8 +99,7 @@ impl qobject::FileSystem {
|
|||||||
)
|
)
|
||||||
.unwrap_or_else(|| ss.find_syntax_plain_text());
|
.unwrap_or_else(|| ss.find_syntax_plain_text());
|
||||||
let mut highlighter = HighlightLines::new(lang, theme);
|
let mut highlighter = HighlightLines::new(lang, theme);
|
||||||
// If you care about the background, see `start_highlighted_html_snippet(theme);`.
|
let (mut output, _bg) = start_highlighted_html_snippet(theme);
|
||||||
let mut output = String::from("<pre>\n");
|
|
||||||
for line in LinesWithEndings::from(lines.as_str()) {
|
for line in LinesWithEndings::from(lines.as_str()) {
|
||||||
let regions = highlighter
|
let regions = highlighter
|
||||||
.highlight_line(line, &ss)
|
.highlight_line(line, &ss)
|
||||||
|
|||||||
Reference in New Issue
Block a user