fix: restore lost changes
C++ / fmt (pull_request) Failing after 3s
C++ / build (pull_request) Failing after 9s
C++ / clang-tidy (pull_request) Failing after 9s
JS/TS / fmt (pull_request) Successful in 7s
JS/TS / lint (pull_request) Successful in 8s
Python / static (pull_request) Successful in 25s
Rust / build (pull_request) Successful in 50s
Rust / fmt (pull_request) Successful in 30s
Python / verify (pull_request) Successful in 1m44s
Rust / clippy (pull_request) Successful in 45s
C++ / fmt (pull_request) Failing after 3s
C++ / build (pull_request) Failing after 9s
C++ / clang-tidy (pull_request) Failing after 9s
JS/TS / fmt (pull_request) Successful in 7s
JS/TS / lint (pull_request) Successful in 8s
Python / static (pull_request) Successful in 25s
Rust / build (pull_request) Successful in 50s
Rust / fmt (pull_request) Successful in 30s
Python / verify (pull_request) Successful in 1m44s
Rust / clippy (pull_request) Successful in 45s
This commit is contained in:
@@ -20,7 +20,7 @@ BusyIndicator {
|
|||||||
property int animState
|
property int animState
|
||||||
property color bgColor: Colors.palette.m3secondaryContainer
|
property color bgColor: Colors.palette.m3secondaryContainer
|
||||||
property color fgColor: Colors.palette.m3primary
|
property color fgColor: Colors.palette.m3primary
|
||||||
property real implicitSize: Tokens.font.size.normal * 3
|
property real implicitSize: Tokens.font.body.medium.pointSize * 3
|
||||||
property real internalStrokeWidth: strokeWidth
|
property real internalStrokeWidth: strokeWidth
|
||||||
readonly property alias progress: manager.progress
|
readonly property alias progress: manager.progress
|
||||||
property real strokeWidth: Tokens.padding.extraSmall * 0.8
|
property real strokeWidth: Tokens.padding.extraSmall * 0.8
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ PersistentProperties {
|
|||||||
property date dashboardDate: new Date()
|
property date dashboardDate: new Date()
|
||||||
|
|
||||||
// Sidebar state
|
// Sidebar state
|
||||||
property int sidebarTab
|
property int sidebarTab: 0
|
||||||
property list<string> expandedNotifs: []
|
property list<string> expandedNotifs: []
|
||||||
|
|
||||||
// Utilities state
|
// Utilities state
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ TextArea {
|
|||||||
|
|
||||||
color: Colors.palette.m3onSurface
|
color: Colors.palette.m3onSurface
|
||||||
cursorVisible: !readOnly
|
cursorVisible: !readOnly
|
||||||
font.pointSize: Tokens.font.size.small
|
font: Tokens.font.body.small
|
||||||
implicitHeight: contentHeight + topPadding + bottomPadding
|
implicitHeight: contentHeight + topPadding + bottomPadding
|
||||||
implicitWidth: contentWidth + leftPadding + rightPadding
|
implicitWidth: contentWidth + leftPadding + rightPadding
|
||||||
placeholderTextColor: Colors.palette.m3onSurfaceVariant // No anim cause placeholder is custom
|
placeholderTextColor: Colors.palette.m3onSurfaceVariant // No anim cause placeholder is custom
|
||||||
|
|||||||
@@ -11,22 +11,18 @@ TextEdit {
|
|||||||
|
|
||||||
color: Colors.palette.m3onSurface
|
color: Colors.palette.m3onSurface
|
||||||
cursorVisible: !readOnly
|
cursorVisible: !readOnly
|
||||||
font.pointSize: Tokens.font.size.small
|
font: Tokens.font.body.small
|
||||||
font.family: Config.appearance.font.family.sans
|
|
||||||
renderType: TextField.NativeRendering
|
renderType: TextField.NativeRendering
|
||||||
selectedTextColor: color
|
selectedTextColor: color
|
||||||
selectionColor: Qt.alpha(Colors.palette.m3primary, 0.4)
|
selectionColor: Qt.alpha(Colors.palette.m3primary, 0.4)
|
||||||
verticalAlignment: TextInput.AlignVCenter
|
verticalAlignment: TextInput.AlignVCenter
|
||||||
|
|
||||||
Behavior on color {
|
Behavior on color {
|
||||||
CAnim {
|
CAnim {}
|
||||||
}
|
|
||||||
}
|
|
||||||
cursorDelegate: Item {
|
|
||||||
}
|
}
|
||||||
|
cursorDelegate: Item {}
|
||||||
Behavior on selectionColor {
|
Behavior on selectionColor {
|
||||||
CAnim {
|
CAnim {}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CustomRect {
|
CustomRect {
|
||||||
|
|||||||
@@ -455,7 +455,7 @@ Item {
|
|||||||
|
|
||||||
MaterialIcon {
|
MaterialIcon {
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
font.pointSize: Tokens.font.size.large
|
fontStyle: Tokens.font.icon.large
|
||||||
text: thumb.fileIcon(thumb.modelData?.mimeType ?? "")
|
text: thumb.fileIcon(thumb.modelData?.mimeType ?? "")
|
||||||
visible: !thumb.modelData?.isImage ?? false
|
visible: !thumb.modelData?.isImage ?? false
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -67,7 +67,7 @@ CustomClippingRect {
|
|||||||
anchors.leftMargin: Tokens.padding.large
|
anchors.leftMargin: Tokens.padding.large
|
||||||
anchors.top: parent.top
|
anchors.top: parent.top
|
||||||
anchors.topMargin: Tokens.padding.large
|
anchors.topMargin: Tokens.padding.large
|
||||||
font.pointSize: Tokens.font.size.extraLarge
|
fontStyle: Tokens.font.icon.extraLarge
|
||||||
text: root.modelData.icon || "check"
|
text: root.modelData.icon || "check"
|
||||||
color: Colors.palette.m3onSurface
|
color: Colors.palette.m3onSurface
|
||||||
}
|
}
|
||||||
@@ -134,7 +134,7 @@ CustomClippingRect {
|
|||||||
anchors.leftMargin: readOnly ? 0 : Tokens.padding.large
|
anchors.leftMargin: readOnly ? 0 : Tokens.padding.large
|
||||||
anchors.top: parent.top
|
anchors.top: parent.top
|
||||||
anchors.topMargin: readOnly ? Tokens.padding.small : Tokens.padding.extraSmall * 2
|
anchors.topMargin: readOnly ? Tokens.padding.small : Tokens.padding.extraSmall * 2
|
||||||
font.pointSize: Tokens.font.size.normal
|
font: Tokens.font.body.medium
|
||||||
text: root.modelData.title || qsTr("New chat")
|
text: root.modelData.title || qsTr("New chat")
|
||||||
readOnly: true
|
readOnly: true
|
||||||
color: Colors.palette.m3onSurface
|
color: Colors.palette.m3onSurface
|
||||||
@@ -192,7 +192,7 @@ CustomClippingRect {
|
|||||||
anchors.topMargin: Tokens.spacing.extraSmall
|
anchors.topMargin: Tokens.spacing.extraSmall
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
font.pointSize: Tokens.font.size.small
|
font: Tokens.font.label.small
|
||||||
color: Colors.palette.m3onSurfaceVariant
|
color: Colors.palette.m3onSurfaceVariant
|
||||||
text: qsTr("Created on: %1").arg(root.modelData.createdAt.toLocaleString(Qt.locale("en_US"), "MMM d, yyyy - h:mm AP"))
|
text: qsTr("Created on: %1").arg(root.modelData.createdAt.toLocaleString(Qt.locale("en_US"), "MMM d, yyyy - h:mm AP"))
|
||||||
opacity: root.expanded ? 1 : 0
|
opacity: root.expanded ? 1 : 0
|
||||||
@@ -208,7 +208,7 @@ CustomClippingRect {
|
|||||||
anchors.top: created.bottom
|
anchors.top: created.bottom
|
||||||
anchors.topMargin: Tokens.spacing.small
|
anchors.topMargin: Tokens.spacing.small
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
font.pointSize: Tokens.font.size.small
|
font: Tokens.font.label.small
|
||||||
color: Colors.palette.m3onSurfaceVariant
|
color: Colors.palette.m3onSurfaceVariant
|
||||||
text: qsTr("Updated on: ")
|
text: qsTr("Updated on: ")
|
||||||
opacity: root.expanded ? 1 : 0
|
opacity: root.expanded ? 1 : 0
|
||||||
@@ -225,7 +225,7 @@ CustomClippingRect {
|
|||||||
anchors.top: title.bottom
|
anchors.top: title.bottom
|
||||||
anchors.topMargin: Tokens.spacing.extraSmall
|
anchors.topMargin: Tokens.spacing.extraSmall
|
||||||
color: Colors.palette.m3onSurfaceVariant
|
color: Colors.palette.m3onSurfaceVariant
|
||||||
font.pointSize: Tokens.font.size.small
|
font: Tokens.font.label.small
|
||||||
text: root.modelData.updatedAt.toLocaleString(Qt.locale("en_US"), "MMM d, yyyy - h:mm AP")
|
text: root.modelData.updatedAt.toLocaleString(Qt.locale("en_US"), "MMM d, yyyy - h:mm AP")
|
||||||
|
|
||||||
states: State {
|
states: State {
|
||||||
@@ -256,7 +256,7 @@ CustomClippingRect {
|
|||||||
y: infoContainer.implicitHeight + topMargin
|
y: infoContainer.implicitHeight + topMargin
|
||||||
elide: Text.ElideRight
|
elide: Text.ElideRight
|
||||||
color: Colors.palette.m3onSurfaceVariant
|
color: Colors.palette.m3onSurfaceVariant
|
||||||
font.pointSize: Tokens.font.size.small
|
font: Tokens.font.body.small
|
||||||
maximumLineCount: 1
|
maximumLineCount: 1
|
||||||
opacity: !root.expanded && !root.slim ? 1 : 0
|
opacity: !root.expanded && !root.slim ? 1 : 0
|
||||||
text: root.modelData.messagesModel.lastMessage?.activeGeneration.content.replace(/\s+/g, " ").trim() ?? qsTr("No messages yet")
|
text: root.modelData.messagesModel.lastMessage?.activeGeneration.content.replace(/\s+/g, " ").trim() ?? qsTr("No messages yet")
|
||||||
@@ -323,7 +323,7 @@ CustomClippingRect {
|
|||||||
fillWidth: true
|
fillWidth: true
|
||||||
shapeMorph: true
|
shapeMorph: true
|
||||||
isRound: true
|
isRound: true
|
||||||
font.pointSize: Tokens.font.size.large
|
font: Tokens.font.icon.medium
|
||||||
inactiveColor: Colors.layer(Colors.palette.m3surfaceContainerHighest, 3)
|
inactiveColor: Colors.layer(Colors.palette.m3surfaceContainerHighest, 3)
|
||||||
inactiveOnColor: Colors.palette.m3onSurfaceVariant
|
inactiveOnColor: Colors.palette.m3onSurfaceVariant
|
||||||
|
|
||||||
@@ -336,7 +336,7 @@ CustomClippingRect {
|
|||||||
isToggle: true
|
isToggle: true
|
||||||
fillWidth: true
|
fillWidth: true
|
||||||
shapeMorph: true
|
shapeMorph: true
|
||||||
font.pointSize: Tokens.font.size.large
|
font: Tokens.font.icon.medium
|
||||||
isRound: true
|
isRound: true
|
||||||
inactiveColor: Colors.layer(Colors.palette.m3surfaceContainerHighest, 3)
|
inactiveColor: Colors.layer(Colors.palette.m3surfaceContainerHighest, 3)
|
||||||
inactiveOnColor: Colors.palette.m3onSurfaceVariant
|
inactiveOnColor: Colors.palette.m3onSurfaceVariant
|
||||||
|
|||||||
@@ -156,7 +156,7 @@ Item {
|
|||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
text: modelsContainer.expanded ? "unfold_less" : "unfold_more"
|
text: modelsContainer.expanded ? "unfold_less" : "unfold_more"
|
||||||
animate: true
|
animate: true
|
||||||
font.pointSize: Tokens.font.size.large
|
fontStyle: Tokens.font.icon.large
|
||||||
visible: modelsList.count > 0
|
visible: modelsList.count > 0
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -229,7 +229,7 @@ Item {
|
|||||||
Layout.alignment: Qt.AlignRight
|
Layout.alignment: Qt.AlignRight
|
||||||
visible: model.selected
|
visible: model.selected
|
||||||
color: Colors.palette.m3onTertiaryContainer
|
color: Colors.palette.m3onTertiaryContainer
|
||||||
font.pointSize: Tokens.font.size.normal
|
fontStyle: Tokens.font.icon.normal
|
||||||
opacity: model.selected ? 1 : 0
|
opacity: model.selected ? 1 : 0
|
||||||
text: "check"
|
text: "check"
|
||||||
|
|
||||||
@@ -405,7 +405,7 @@ Item {
|
|||||||
MaterialIcon {
|
MaterialIcon {
|
||||||
text: fabMenuItem.modelData.icon
|
text: fabMenuItem.modelData.icon
|
||||||
color: Colors.palette.m3onPrimaryContainer
|
color: Colors.palette.m3onPrimaryContainer
|
||||||
font.pointSize: Tokens.font.size.large
|
fontStyle: Tokens.font.icon.large
|
||||||
fill: 1
|
fill: 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ pragma Singleton
|
|||||||
import QtQuick
|
import QtQuick
|
||||||
import Quickshell
|
import Quickshell
|
||||||
import ZShell.Llm
|
import ZShell.Llm
|
||||||
import qs.Helpers
|
import qs.Services
|
||||||
|
|
||||||
Singleton {
|
Singleton {
|
||||||
id: root
|
id: root
|
||||||
@@ -20,7 +20,7 @@ Singleton {
|
|||||||
property bool narrowSidebarExpanded: false
|
property bool narrowSidebarExpanded: false
|
||||||
property bool windowIsWide: false
|
property bool windowIsWide: false
|
||||||
property ShellScreen screen
|
property ShellScreen screen
|
||||||
property bool sidebarVisible: Visibilities.getForActive().sidebar
|
property bool sidebarVisible: ShellState.forActive().sidebar
|
||||||
|
|
||||||
onSidebarVisibleChanged: if (!sidebarVisible)
|
onSidebarVisibleChanged: if (!sidebarVisible)
|
||||||
fabExpanded = false
|
fabExpanded = false
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ Item {
|
|||||||
enabled: root.message.generationCount > 1 && root.message.activeGenerationIndex !== 0
|
enabled: root.message.generationCount > 1 && root.message.activeGenerationIndex !== 0
|
||||||
icon: "chevron_left"
|
icon: "chevron_left"
|
||||||
type: IconButton.Tonal
|
type: IconButton.Tonal
|
||||||
|
isRound: true
|
||||||
|
|
||||||
onClicked: {
|
onClicked: {
|
||||||
if (!root.edit.readOnly)
|
if (!root.edit.readOnly)
|
||||||
@@ -40,8 +41,7 @@ Item {
|
|||||||
IconButton {
|
IconButton {
|
||||||
enabled: false
|
enabled: false
|
||||||
icon: `${root.message.activeGenerationIndex + 1}`
|
icon: `${root.message.activeGenerationIndex + 1}`
|
||||||
label.font.family: Config.appearance.font.family.sans
|
label.font: Tokens.font.body.small
|
||||||
label.font.pointSize: Tokens.font.size.small
|
|
||||||
type: IconButton.Text
|
type: IconButton.Text
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -49,6 +49,7 @@ Item {
|
|||||||
enabled: root.message.generationCount > 1 && root.message.activeGenerationIndex !== root.message.generationCount - 1
|
enabled: root.message.generationCount > 1 && root.message.activeGenerationIndex !== root.message.generationCount - 1
|
||||||
icon: "chevron_right"
|
icon: "chevron_right"
|
||||||
type: IconButton.Tonal
|
type: IconButton.Tonal
|
||||||
|
isRound: true
|
||||||
|
|
||||||
onClicked: {
|
onClicked: {
|
||||||
if (!root.edit.readOnly)
|
if (!root.edit.readOnly)
|
||||||
@@ -76,6 +77,7 @@ Item {
|
|||||||
inactiveOnColor: Colors.palette.m3onSecondary
|
inactiveOnColor: Colors.palette.m3onSecondary
|
||||||
scale: root.edit.readOnly ? 1 : 0
|
scale: root.edit.readOnly ? 1 : 0
|
||||||
visible: !root.isUser
|
visible: !root.isUser
|
||||||
|
isRound: true
|
||||||
|
|
||||||
Behavior on scale {
|
Behavior on scale {
|
||||||
Anim {}
|
Anim {}
|
||||||
@@ -91,6 +93,7 @@ Item {
|
|||||||
inactiveColor: Colors.palette.m3secondary
|
inactiveColor: Colors.palette.m3secondary
|
||||||
inactiveOnColor: Colors.palette.m3onSecondary
|
inactiveOnColor: Colors.palette.m3onSecondary
|
||||||
scale: root.edit.readOnly ? 1 : 0
|
scale: root.edit.readOnly ? 1 : 0
|
||||||
|
isRound: true
|
||||||
|
|
||||||
Behavior on scale {
|
Behavior on scale {
|
||||||
Anim {}
|
Anim {}
|
||||||
@@ -106,6 +109,7 @@ Item {
|
|||||||
inactiveColor: Colors.palette.m3tertiary
|
inactiveColor: Colors.palette.m3tertiary
|
||||||
inactiveOnColor: Colors.palette.m3onTertiary
|
inactiveOnColor: Colors.palette.m3onTertiary
|
||||||
visible: root.isUser
|
visible: root.isUser
|
||||||
|
isRound: true
|
||||||
|
|
||||||
onClicked: {
|
onClicked: {
|
||||||
root.edit.readOnly = !root.edit.readOnly;
|
root.edit.readOnly = !root.edit.readOnly;
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ TextEditBase {
|
|||||||
color: Colors.palette.m3onSurface
|
color: Colors.palette.m3onSurface
|
||||||
readOnly: true
|
readOnly: true
|
||||||
textFormat: Text.MarkdownText
|
textFormat: Text.MarkdownText
|
||||||
font.pointSize: Tokens.font.size.smaller
|
font: Tokens.font.body.small
|
||||||
wrapMode: Text.WrapAtWordBoundaryOrAnywhere
|
wrapMode: Text.WrapAtWordBoundaryOrAnywhere
|
||||||
|
|
||||||
onLinkActivated: link => {
|
onLinkActivated: link => {
|
||||||
|
|||||||
@@ -6,138 +6,138 @@ import qs.Services
|
|||||||
import qs.Modules.Notifications.Sidebar.Chat
|
import qs.Modules.Notifications.Sidebar.Chat
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
property int animOff
|
property int animOff
|
||||||
property Item currentItem
|
property Item currentItem
|
||||||
property bool noAnim: false
|
property bool noAnim: false
|
||||||
property bool loading: false
|
property bool loading: false
|
||||||
property int lastIdx: -1
|
property int lastIdx: -1
|
||||||
|
|
||||||
readonly property Component conversationComp: ChatContent {}
|
readonly property Component conversationComp: ChatContent {}
|
||||||
|
|
||||||
signal requestClose
|
signal requestClose
|
||||||
|
|
||||||
function loadConversation(chat): void {
|
function loadConversation(chat): void {
|
||||||
if (currentItem) {
|
if (currentItem) {
|
||||||
currentItem.destroy();
|
currentItem.destroy();
|
||||||
currentItem = null;
|
currentItem = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!chat)
|
if (!chat)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
root.loading = true;
|
root.loading = true;
|
||||||
|
|
||||||
const incubator = root.conversationComp.incubateObject(container, {
|
const incubator = root.conversationComp.incubateObject(container, {
|
||||||
chatData: chat
|
chatData: chat
|
||||||
});
|
});
|
||||||
|
|
||||||
const attach = () => {
|
const attach = () => {
|
||||||
incubator.object.anchors.fill = container;
|
incubator.object.anchors.fill = container;
|
||||||
incubator.object.requestClose.connect(root.requestClose);
|
incubator.object.requestClose.connect(root.requestClose);
|
||||||
currentItem = incubator.object;
|
currentItem = incubator.object;
|
||||||
root.loading = false;
|
root.loading = false;
|
||||||
if (!noAnim)
|
if (!noAnim)
|
||||||
enterAnim.start();
|
enterAnim.start();
|
||||||
};
|
};
|
||||||
|
|
||||||
if (incubator.status === Component.Ready)
|
if (incubator.status === Component.Ready)
|
||||||
attach();
|
attach();
|
||||||
else
|
else
|
||||||
incubator.onStatusChanged = status => {
|
incubator.onStatusChanged = status => {
|
||||||
if (status === Component.Ready)
|
if (status === Component.Ready)
|
||||||
attach();
|
attach();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
id: container
|
id: container
|
||||||
|
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
layer.enabled: opacity < 1
|
layer.enabled: opacity < 1
|
||||||
objectName: "ConversationContainer"
|
objectName: "ConversationContainer"
|
||||||
|
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
if (ChatState.chatSession)
|
if (ChatState.chatSession)
|
||||||
root.loadConversation(ChatState.chatSession);
|
root.loadConversation(ChatState.chatSession);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
LoadingIndicator {
|
LoadingIndicator {
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
implicitSize: Tokens.font.size.extraLarge * 4
|
implicitSize: Tokens.font.icon.extraLarge.pointSize * 4
|
||||||
opacity: root.loading ? 1 : 0
|
opacity: root.loading ? 1 : 0
|
||||||
visible: opacity > 0
|
visible: opacity > 0
|
||||||
|
|
||||||
Behavior on opacity {
|
Behavior on opacity {
|
||||||
Anim {}
|
Anim {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Connections {
|
Connections {
|
||||||
function onChatSessionChanged(): void {
|
function onChatSessionChanged(): void {
|
||||||
exitAnim.complete();
|
exitAnim.complete();
|
||||||
enterAnim.complete();
|
enterAnim.complete();
|
||||||
|
|
||||||
if (root.noAnim) {
|
if (root.noAnim) {
|
||||||
root.loadConversation(ChatState.chatSession);
|
root.loadConversation(ChatState.chatSession);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
root.animOff = Tokens.padding.small * (ChatState.currentIdx > root.lastIdx ? 1 : -1);
|
root.animOff = Tokens.padding.small * (ChatState.currentIdx > root.lastIdx ? 1 : -1);
|
||||||
root.lastIdx = ChatState.currentIdx;
|
root.lastIdx = ChatState.currentIdx;
|
||||||
exitAnim.start();
|
exitAnim.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
target: ChatState
|
target: ChatState
|
||||||
}
|
}
|
||||||
|
|
||||||
SequentialAnimation {
|
SequentialAnimation {
|
||||||
id: exitAnim
|
id: exitAnim
|
||||||
|
|
||||||
Anim {
|
Anim {
|
||||||
property: "opacity"
|
property: "opacity"
|
||||||
target: container
|
target: container
|
||||||
to: 0
|
to: 0
|
||||||
type: Anim.DefaultEffects
|
type: Anim.DefaultEffects
|
||||||
}
|
}
|
||||||
|
|
||||||
ScriptAction {
|
ScriptAction {
|
||||||
script: root.loadConversation(ChatState.chatSession)
|
script: root.loadConversation(ChatState.chatSession)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SequentialAnimation {
|
SequentialAnimation {
|
||||||
id: enterAnim
|
id: enterAnim
|
||||||
|
|
||||||
PropertyAction {
|
PropertyAction {
|
||||||
property: "topMargin"
|
property: "topMargin"
|
||||||
target: container.anchors
|
target: container.anchors
|
||||||
value: root.animOff
|
value: root.animOff
|
||||||
}
|
}
|
||||||
|
|
||||||
PropertyAction {
|
PropertyAction {
|
||||||
property: "bottomMargin"
|
property: "bottomMargin"
|
||||||
target: container.anchors
|
target: container.anchors
|
||||||
value: -root.animOff
|
value: -root.animOff
|
||||||
}
|
}
|
||||||
|
|
||||||
ParallelAnimation {
|
ParallelAnimation {
|
||||||
Anim {
|
Anim {
|
||||||
from: 0
|
from: 0
|
||||||
property: "opacity"
|
property: "opacity"
|
||||||
target: container
|
target: container
|
||||||
to: 1
|
to: 1
|
||||||
type: Anim.SlowEffects
|
type: Anim.SlowEffects
|
||||||
}
|
}
|
||||||
|
|
||||||
Anim {
|
Anim {
|
||||||
properties: "topMargin,bottomMargin"
|
properties: "topMargin,bottomMargin"
|
||||||
target: container.anchors
|
target: container.anchors
|
||||||
to: 0
|
to: 0
|
||||||
type: Anim.SlowEffects
|
type: Anim.SlowEffects
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,8 +32,7 @@ CustomRect {
|
|||||||
function onHighlightSpans(token, spans) {
|
function onHighlightSpans(token, spans) {
|
||||||
if (token !== root.highlightToken)
|
if (token !== root.highlightToken)
|
||||||
return;
|
return;
|
||||||
if (root.code !== root.requestedCode ||
|
if (root.code !== root.requestedCode || root.language !== root.requestedLanguage)
|
||||||
root.language !== root.requestedLanguage)
|
|
||||||
return;
|
return;
|
||||||
html = spans.length ? root.highlightedHtml(root.code, spans) : "";
|
html = spans.length ? root.highlightedHtml(root.code, spans) : "";
|
||||||
colored = root.visible && html.length > 0;
|
colored = root.visible && html.length > 0;
|
||||||
@@ -84,15 +83,13 @@ CustomRect {
|
|||||||
// whitespace kept, mid-line runs collapsed, tabs as single spaces) so the
|
// whitespace kept, mid-line runs collapsed, tabs as single spaces) so the
|
||||||
// plain and colored layouts are identical.
|
// plain and colored layouts are identical.
|
||||||
function plainForDisplay(code): string {
|
function plainForDisplay(code): string {
|
||||||
return code.split("\n")
|
return code.split("\n").map(line => {
|
||||||
.map(line => {
|
const i = line.search(/\S/);
|
||||||
const i = line.search(/\S/);
|
if (i < 0)
|
||||||
if (i < 0)
|
return "";
|
||||||
return "";
|
const lead = line.slice(0, i).replace(/\t/g, " ");
|
||||||
const lead = line.slice(0, i).replace(/\t/g, " ");
|
return lead + line.slice(i).replace(/\s+/g, " ").replace(/\s+$/, "");
|
||||||
return lead + line.slice(i).replace(/\s+/g, " ").replace(/\s+$/, "");
|
}).join("\n");
|
||||||
})
|
|
||||||
.join("\n");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function highlightedHtml(code, spans): string {
|
function highlightedHtml(code, spans): string {
|
||||||
@@ -136,7 +133,7 @@ CustomRect {
|
|||||||
refreshTimer.restart();
|
refreshTimer.restart();
|
||||||
}
|
}
|
||||||
onVisibleChanged: if (root.visible)
|
onVisibleChanged: if (root.visible)
|
||||||
refreshTimer.restart();
|
refreshTimer.restart()
|
||||||
|
|
||||||
Timer {
|
Timer {
|
||||||
id: refreshTimer
|
id: refreshTimer
|
||||||
@@ -223,7 +220,7 @@ CustomRect {
|
|||||||
|
|
||||||
Layout.alignment: Qt.AlignVCenter
|
Layout.alignment: Qt.AlignVCenter
|
||||||
color: root.codeHeaderColor
|
color: root.codeHeaderColor
|
||||||
font.pointSize: Tokens.font.size.small
|
font: Tokens.font.label.small
|
||||||
text: CodeIcons.name(root.language)
|
text: CodeIcons.name(root.language)
|
||||||
visible: root.language.length > 0
|
visible: root.language.length > 0
|
||||||
}
|
}
|
||||||
@@ -289,8 +286,7 @@ CustomRect {
|
|||||||
color: CodeColors.active.normal
|
color: CodeColors.active.normal
|
||||||
layer.enabled: true
|
layer.enabled: true
|
||||||
clip: false
|
clip: false
|
||||||
font.family: Config.appearance.font.family.mono
|
font: Tokens.font.mono.small
|
||||||
font.pointSize: Tokens.font.size.small
|
|
||||||
textFormat: root.colored ? Text.RichText : Text.PlainText
|
textFormat: root.colored ? Text.RichText : Text.PlainText
|
||||||
text: root.colored ? root.html : root.plainForDisplay(root.code)
|
text: root.colored ? root.html : root.plainForDisplay(root.code)
|
||||||
readOnly: true
|
readOnly: true
|
||||||
|
|||||||
@@ -85,7 +85,7 @@ Item {
|
|||||||
animateCursor: false
|
animateCursor: false
|
||||||
color: root.isUser ? Colors.palette.m3onPrimary : Colors.palette.m3onSurface
|
color: root.isUser ? Colors.palette.m3onPrimary : Colors.palette.m3onSurface
|
||||||
cursor.color: root.isUser ? Colors.palette.m3onPrimary : Colors.palette.m3primary
|
cursor.color: root.isUser ? Colors.palette.m3onPrimary : Colors.palette.m3primary
|
||||||
font.pointSize: Tokens.font.size.smaller
|
font: Tokens.font.body.small
|
||||||
readOnly: true
|
readOnly: true
|
||||||
selectionColor: Qt.alpha((root.isUser ? Colors.palette.m3onPrimary : Colors.palette.m3primary), 0.4)
|
selectionColor: Qt.alpha((root.isUser ? Colors.palette.m3onPrimary : Colors.palette.m3primary), 0.4)
|
||||||
text: root.isUser ? root.segment.text : ""
|
text: root.isUser ? root.segment.text : ""
|
||||||
|
|||||||
@@ -93,7 +93,7 @@ Item {
|
|||||||
|
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
|
|
||||||
font.pointSize: Tokens.font.size.large
|
font: Tokens.font.headline.small
|
||||||
elide: CustomText.ElideRight
|
elide: CustomText.ElideRight
|
||||||
color: Colors.palette.m3onErrorContainer
|
color: Colors.palette.m3onErrorContainer
|
||||||
|
|
||||||
@@ -120,7 +120,7 @@ Item {
|
|||||||
isRound: true
|
isRound: true
|
||||||
icon: "close"
|
icon: "close"
|
||||||
type: IconButton.Text
|
type: IconButton.Text
|
||||||
font.pointSize: Tokens.font.size.large
|
font: Tokens.font.icon.medium
|
||||||
|
|
||||||
onClicked: exitAnim.start()
|
onClicked: exitAnim.start()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -62,13 +62,12 @@ Column {
|
|||||||
text: modelData.text
|
text: modelData.text
|
||||||
textFormat: Text.MarkdownText
|
textFormat: Text.MarkdownText
|
||||||
readOnly: true
|
readOnly: true
|
||||||
font.bold: true
|
font: {
|
||||||
font.pointSize: {
|
|
||||||
if (modelData.level <= 1)
|
if (modelData.level <= 1)
|
||||||
return Tokens.font.size.large;
|
return Tokens.font.title.builders.large.weight(Font.Bold).build();
|
||||||
if (modelData.level === 2)
|
if (modelData.level === 2)
|
||||||
return Tokens.font.size.normal;
|
return Tokens.font.title.builders.medium.weight(Font.Bold).build();
|
||||||
return Tokens.font.size.smaller;
|
return Tokens.font.title.builders.small.weight(Font.Bold).build();
|
||||||
}
|
}
|
||||||
wrapMode: Text.WrapAtWordBoundaryOrAnywhere
|
wrapMode: Text.WrapAtWordBoundaryOrAnywhere
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ Item {
|
|||||||
|
|
||||||
required property string latex
|
required property string latex
|
||||||
property color mathColor: Colors.palette.m3onSurface
|
property color mathColor: Colors.palette.m3onSurface
|
||||||
property real fontSize: Tokens.font.size.large
|
property font font: Tokens.font.headline.medium
|
||||||
|
|
||||||
implicitHeight: Math.max(equationImage.height, fallbackText.contentHeight) + Tokens.padding.small * 2
|
implicitHeight: Math.max(equationImage.height, fallbackText.contentHeight) + Tokens.padding.small * 2
|
||||||
|
|
||||||
@@ -18,7 +18,7 @@ Item {
|
|||||||
|
|
||||||
latex: root.latex
|
latex: root.latex
|
||||||
color: root.mathColor
|
color: root.mathColor
|
||||||
fontPointSize: root.fontSize
|
fontPointSize: root.font.pointSize
|
||||||
devicePixelRatio: Screen.devicePixelRatio
|
devicePixelRatio: Screen.devicePixelRatio
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -39,8 +39,7 @@ Item {
|
|||||||
|
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
color: root.mathColor
|
color: root.mathColor
|
||||||
font.family: Config.appearance.font.family.mono
|
font: Tokens.font.mono.medium
|
||||||
font.pointSize: Tokens.font.size.small
|
|
||||||
text: root.latex
|
text: root.latex
|
||||||
wrapMode: Text.WrapAtWordBoundaryOrAnywhere
|
wrapMode: Text.WrapAtWordBoundaryOrAnywhere
|
||||||
visible: !math.ok
|
visible: !math.ok
|
||||||
|
|||||||
@@ -231,7 +231,7 @@ MouseArea {
|
|||||||
|
|
||||||
MaterialIcon {
|
MaterialIcon {
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
font.pointSize: Tokens.font.size.extraLarge
|
fontStyle: Tokens.font.icon.extraLarge
|
||||||
text: thumb.fileIcon(thumb.modelData?.mimeType ?? "")
|
text: thumb.fileIcon(thumb.modelData?.mimeType ?? "")
|
||||||
visible: !thumb.modelData?.isImage ?? false
|
visible: !thumb.modelData?.isImage ?? false
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -70,7 +70,7 @@ Item {
|
|||||||
IconButton {
|
IconButton {
|
||||||
id: expandBtn
|
id: expandBtn
|
||||||
|
|
||||||
font.pointSize: Tokens.font.size.large
|
font: Tokens.font.icon.medium
|
||||||
icon: "keyboard_arrow_down"
|
icon: "keyboard_arrow_down"
|
||||||
inactiveOnColor: hovered ? Colors.palette.m3onSurface : Colors.palette.m3outline
|
inactiveOnColor: hovered ? Colors.palette.m3onSurface : Colors.palette.m3outline
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
@@ -91,7 +91,7 @@ Item {
|
|||||||
id: collapsedText
|
id: collapsedText
|
||||||
|
|
||||||
color: Colors.palette.m3outline
|
color: Colors.palette.m3outline
|
||||||
font.pointSize: Tokens.font.size.small
|
font: Tokens.font.label.small
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.leftMargin: Tokens.spacing.medium
|
Layout.leftMargin: Tokens.spacing.medium
|
||||||
text: {
|
text: {
|
||||||
@@ -139,7 +139,7 @@ Item {
|
|||||||
CustomText {
|
CustomText {
|
||||||
id: requestHeader
|
id: requestHeader
|
||||||
text: qsTr("Tool call request")
|
text: qsTr("Tool call request")
|
||||||
font.pointSize: Tokens.font.size.large
|
font: Tokens.font.headline.medium
|
||||||
color: Colors.palette.m3onSurface
|
color: Colors.palette.m3onSurface
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -420,7 +420,7 @@ Item {
|
|||||||
IconButton {
|
IconButton {
|
||||||
id: toolExpandBtn
|
id: toolExpandBtn
|
||||||
|
|
||||||
font.pointSize: Tokens.font.size.large
|
font: Tokens.font.icon.medium
|
||||||
icon: "keyboard_arrow_down"
|
icon: "keyboard_arrow_down"
|
||||||
inactiveOnColor: hovered ? Colors.palette.m3onSurface : Colors.palette.m3outline
|
inactiveOnColor: hovered ? Colors.palette.m3onSurface : Colors.palette.m3outline
|
||||||
rotation: toolCall.expanded ? 180 : 0
|
rotation: toolCall.expanded ? 180 : 0
|
||||||
@@ -609,7 +609,7 @@ Item {
|
|||||||
anchors.topMargin: Tokens.spacing.small
|
anchors.topMargin: Tokens.spacing.small
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
color: Colors.palette.m3outline
|
color: Colors.palette.m3outline
|
||||||
font.pointSize: Tokens.font.size.small
|
font: Tokens.font.body.small
|
||||||
wrapMode: CustomText.WrapAtWordBoundaryOrAnywhere
|
wrapMode: CustomText.WrapAtWordBoundaryOrAnywhere
|
||||||
text: segment.modelData.type === LlmSegment.Type.Reasoning ? segment.modelData.text : qsTr("%1 %2").arg(content.prettyTool(segment.modelData)).arg(content.toolTarget(segment.modelData))
|
text: segment.modelData.type === LlmSegment.Type.Reasoning ? segment.modelData.text : qsTr("%1 %2").arg(content.prettyTool(segment.modelData)).arg(content.toolTarget(segment.modelData))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ Singleton {
|
|||||||
|
|
||||||
function create(parent: Item, props: var): void {
|
function create(parent: Item, props: var): void {
|
||||||
chatComp.createObject(parent ?? dummy, props);
|
chatComp.createObject(parent ?? dummy, props);
|
||||||
Visibilities.getForActive().sidebar = false;
|
ShellState.forActive().sidebar = false;
|
||||||
ChatState.isWindow = true;
|
ChatState.isWindow = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ Item {
|
|||||||
|
|
||||||
property int breakpoint: Math.round(Config.sidebar.sizes.width * 2) + Tokens.spacing.medium * 2 + Tokens.padding.medium * 3
|
property int breakpoint: Math.round(Config.sidebar.sizes.width * 2) + Tokens.spacing.medium * 2 + Tokens.padding.medium * 3
|
||||||
property color blobColor: Colors.tPalette.m3surfaceContainerLow
|
property color blobColor: Colors.tPalette.m3surfaceContainerLow
|
||||||
readonly property int iconSize: Math.round(Tokens.font.size.extraLarge * (96 / 72)) + Tokens.padding.large * 2
|
readonly property int iconSize: Math.round(Tokens.font.icon.extraLarge.pointSize * (96 / 72)) + Tokens.padding.large * 2
|
||||||
property alias conversationModel: sidebar.model
|
property alias conversationModel: sidebar.model
|
||||||
property bool chatOpen: ChatState.chatSession !== null
|
property bool chatOpen: ChatState.chatSession !== null
|
||||||
|
|
||||||
@@ -174,7 +174,7 @@ Item {
|
|||||||
MaterialIcon {
|
MaterialIcon {
|
||||||
Layout.alignment: Qt.AlignCenter
|
Layout.alignment: Qt.AlignCenter
|
||||||
text: "chat_bubble_off"
|
text: "chat_bubble_off"
|
||||||
font.pointSize: Tokens.font.size.extraLarge
|
fontStyle: Tokens.font.icon.extraLarge
|
||||||
color: Colors.tPalette.m3onSurfaceVariant
|
color: Colors.tPalette.m3onSurfaceVariant
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ Item {
|
|||||||
Connections {
|
Connections {
|
||||||
function onIsWindowChanged(): void {
|
function onIsWindowChanged(): void {
|
||||||
if (ChatState.isWindow)
|
if (ChatState.isWindow)
|
||||||
root.screenState.dashboardTab = 0;
|
root.screenState.sidebarTab = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
target: ChatState
|
target: ChatState
|
||||||
@@ -46,9 +46,9 @@ Item {
|
|||||||
anchors.bottom: parent.bottom
|
anchors.bottom: parent.bottom
|
||||||
anchors.top: parent.top
|
anchors.top: parent.top
|
||||||
implicitWidth: parent.width
|
implicitWidth: parent.width
|
||||||
opacity: root.screenState.dashboardTab === 0 ? 1 : 0
|
opacity: root.screenState.sidebarTab === 0 ? 1 : 0
|
||||||
visible: opacity > 0
|
visible: opacity > 0
|
||||||
x: root.screenState.dashboardTab === 0 ? 0 : -root.width
|
x: root.screenState.sidebarTab === 0 ? 0 : -root.width
|
||||||
|
|
||||||
Behavior on opacity {
|
Behavior on opacity {
|
||||||
Anim {}
|
Anim {}
|
||||||
@@ -80,9 +80,9 @@ Item {
|
|||||||
sourceComponent: Item {
|
sourceComponent: Item {
|
||||||
id: chatPage
|
id: chatPage
|
||||||
|
|
||||||
opacity: root.screenState.dashboardTab === 1 ? 1 : 0
|
opacity: root.screenState.sidebarTab === 1 ? 1 : 0
|
||||||
visible: opacity > 0
|
visible: opacity > 0
|
||||||
x: root.screenState.dashboardTab === 0 ? root.width : 0
|
x: root.screenState.sidebarTab === 0 ? root.width : 0
|
||||||
z: 1
|
z: 1
|
||||||
|
|
||||||
Behavior on opacity {
|
Behavior on opacity {
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ Item {
|
|||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
anchors.top: parent.top
|
anchors.top: parent.top
|
||||||
background: null
|
background: null
|
||||||
currentIndex: root.screenState.dashboardTab
|
currentIndex: root.screenState.sidebarTab
|
||||||
implicitHeight: contentHeight
|
implicitHeight: contentHeight
|
||||||
|
|
||||||
contentItem: RowLayout {
|
contentItem: RowLayout {
|
||||||
@@ -108,7 +108,7 @@ Item {
|
|||||||
color: tab.current ? Colors.palette.m3onPrimary : Colors.palette.m3onSurface
|
color: tab.current ? Colors.palette.m3onPrimary : Colors.palette.m3onSurface
|
||||||
radius: Tokens.rounding.small
|
radius: Tokens.rounding.small
|
||||||
|
|
||||||
onClicked: root.screenState.dashboardTab = tab.TabBar.index
|
onClicked: root.screenState.sidebarTab = tab.TabBar.index
|
||||||
}
|
}
|
||||||
|
|
||||||
MaterialIcon {
|
MaterialIcon {
|
||||||
@@ -118,7 +118,7 @@ Item {
|
|||||||
anchors.horizontalCenter: parent.horizontalCenter
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
color: tab.current ? Colors.palette.m3primary : Colors.palette.m3onSurfaceVariant
|
color: tab.current ? Colors.palette.m3primary : Colors.palette.m3onSurfaceVariant
|
||||||
fill: tab.current ? 1 : 0
|
fill: tab.current ? 1 : 0
|
||||||
font.pointSize: 18
|
fontStyle: Tokens.font.icon.large
|
||||||
text: tab.iconName
|
text: tab.iconName
|
||||||
|
|
||||||
Behavior on fill {
|
Behavior on fill {
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ DialogRowButton {
|
|||||||
|
|
||||||
property var initialSelect
|
property var initialSelect
|
||||||
property var selectedItem
|
property var selectedItem
|
||||||
property var initialSelect
|
|
||||||
|
|
||||||
function keyFor(item: var): string {
|
function keyFor(item: var): string {
|
||||||
return item.id;
|
return item.id;
|
||||||
|
|||||||
@@ -57,7 +57,6 @@ PageBase {
|
|||||||
icon: "add"
|
icon: "add"
|
||||||
last: true
|
last: true
|
||||||
label: qsTr("Add entry")
|
label: qsTr("Add entry")
|
||||||
last: true
|
|
||||||
model: {
|
model: {
|
||||||
const present = new Set(Config.bar.tray.statusIcons.values.map(item => item.id));
|
const present = new Set(Config.bar.tray.statusIcons.values.map(item => item.id));
|
||||||
return Object.keys(root.builtinIcons).filter(id => !present.has(id)).map(id => ({
|
return Object.keys(root.builtinIcons).filter(id => !present.has(id)).map(id => ({
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
qml_module(ZShell
|
qml_module(ZShell
|
||||||
URI ZShell
|
URI ZShell
|
||||||
|
INCLUDE_PREFIX core
|
||||||
SOURCES
|
SOURCES
|
||||||
writefile.hpp writefile.cpp
|
writefile.hpp writefile.cpp
|
||||||
appdb.hpp appdb.cpp
|
appdb.hpp appdb.cpp
|
||||||
|
|||||||
@@ -1,36 +1,29 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "configobject.hpp"
|
|
||||||
#include <qhashfunctions.h>
|
#include <qhashfunctions.h>
|
||||||
#include <qobject.h>
|
#include <qobject.h>
|
||||||
#include <qqmlintegration.h>
|
#include <qqmlintegration.h>
|
||||||
|
|
||||||
|
#include "common.hpp"
|
||||||
|
|
||||||
namespace ZShell::config {
|
namespace ZShell::config {
|
||||||
|
|
||||||
class LlmAppearance : public ConfigObject {
|
class LlmAppearance : public settings::ObjectNode {
|
||||||
Q_OBJECT
|
CONFIG_NODE(LlmAppearance, settings::ObjectNode)
|
||||||
QML_ANONYMOUS
|
|
||||||
|
|
||||||
CFG_PROPERTY(QString, scheme, QStringLiteral("tokyoNight"))
|
CONFIG_PROPERTY(QString, scheme, QStringLiteral("tokyoNight"))
|
||||||
|
|
||||||
public:
|
|
||||||
explicit LlmAppearance(QObject* parent = nullptr) : ConfigObject(parent) {}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class Llm : public ConfigObject {
|
class Llm : public settings::ObjectNode {
|
||||||
Q_OBJECT
|
CONFIG_NODE(Llm, settings::ObjectNode)
|
||||||
QML_ANONYMOUS
|
|
||||||
|
|
||||||
CFG_PROPERTY(QString, endpoint, "http://localhost:8080")
|
CONFIG_PROPERTY(QString, endpoint, "http://localhost:8080")
|
||||||
CFG_PROPERTY(QString, model, "")
|
CONFIG_PROPERTY(QString, model, "")
|
||||||
CFG_PROPERTY(double, temperature, 0.7)
|
CONFIG_PROPERTY(double, temperature, 0.7)
|
||||||
CFG_PROPERTY(bool, tools, true)
|
CONFIG_PROPERTY(bool, tools, true)
|
||||||
CFG_PROPERTY(bool, sandbox, true)
|
CONFIG_PROPERTY(bool, sandbox, true)
|
||||||
CFG_PROPERTY(bool, enabled, true)
|
CONFIG_PROPERTY(bool, enabled, true)
|
||||||
CONFIG_SUBOBJECT(LlmAppearance, appearance)
|
CONFIG_SUBOBJECT(LlmAppearance, appearance)
|
||||||
|
|
||||||
public:
|
|
||||||
explicit Llm(QObject* parent = nullptr)
|
|
||||||
: ConfigObject(parent), m_appearance(new LlmAppearance(this)) {}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace ZShell::config
|
} // namespace ZShell::config
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
#include "dock.hpp"
|
#include "dock.hpp"
|
||||||
#include "general.hpp"
|
#include "general.hpp"
|
||||||
#include "launcher.hpp"
|
#include "launcher.hpp"
|
||||||
|
#include "llm.hpp"
|
||||||
#include "lock.hpp"
|
#include "lock.hpp"
|
||||||
#include "notifs.hpp"
|
#include "notifs.hpp"
|
||||||
#include "osd.hpp"
|
#include "osd.hpp"
|
||||||
@@ -42,6 +43,7 @@ class ConfigRoot : public settings::RootNode {
|
|||||||
CONFIG_SUBOBJECT(Dock, dock)
|
CONFIG_SUBOBJECT(Dock, dock)
|
||||||
CONFIG_SUBOBJECT(General, general)
|
CONFIG_SUBOBJECT(General, general)
|
||||||
CONFIG_SUBOBJECT(Launcher, launcher)
|
CONFIG_SUBOBJECT(Launcher, launcher)
|
||||||
|
CONFIG_SUBOBJECT(Llm, llm)
|
||||||
CONFIG_SUBOBJECT(Lock, lock)
|
CONFIG_SUBOBJECT(Lock, lock)
|
||||||
CONFIG_SUBOBJECT(Notifs, notifs)
|
CONFIG_SUBOBJECT(Notifs, notifs)
|
||||||
CONFIG_SUBOBJECT(Osd, osd)
|
CONFIG_SUBOBJECT(Osd, osd)
|
||||||
|
|||||||
@@ -1,38 +1,14 @@
|
|||||||
# cmark-gfm: markdown -> block structure (pkg-config; no CMake config
|
|
||||||
# package is installed).
|
|
||||||
pkg_check_modules(CMARK_GFM REQUIRED IMPORTED_TARGET libcmark-gfm)
|
pkg_check_modules(CMARK_GFM REQUIRED IMPORTED_TARGET libcmark-gfm)
|
||||||
|
|
||||||
# tree-sitter runtime for code block highlighting (grammars are
|
|
||||||
# dlopen()'d at runtime and optional).
|
|
||||||
pkg_check_modules(TREE_SITTER REQUIRED IMPORTED_TARGET tree-sitter)
|
pkg_check_modules(TREE_SITTER REQUIRED IMPORTED_TARGET tree-sitter)
|
||||||
|
|
||||||
# JKQTMathText (JKQtPlotter) for LaTeX rendering. The config files live
|
|
||||||
# in a shared JKQTPlotter6 directory, not one named after the package.
|
|
||||||
find_path(JKQTPlotter6_CMAKE_DIR
|
find_path(JKQTPlotter6_CMAKE_DIR
|
||||||
NAMES JKQTMathText6Config.cmake
|
NAMES JKQTMathText6Config.cmake
|
||||||
HINTS /usr/lib/cmake/JKQTPlotter6 /usr/local/lib/cmake/JKQTPlotter6
|
HINTS /usr/lib/cmake/JKQTPlotter6 /usr/local/lib/cmake/JKQTPlotter6
|
||||||
DOC "Directory containing the JKQtPlotter cmake package files")
|
DOC "Directory containing the JKQtPlotter cmake package files")
|
||||||
find_package(JKQTMathText6 REQUIRED PATHS "${JKQTPlotter6_CMAKE_DIR}")
|
find_package(JKQTMathText6 REQUIRED PATHS "${JKQTPlotter6_CMAKE_DIR}")
|
||||||
|
|
||||||
# --- tree-sitter grammar discovery (configure time) ---
|
|
||||||
#
|
|
||||||
# Discover installed tree-sitter grammars — system packages
|
|
||||||
# (libtree-sitter-<lang>.so) and the parsers Neovim's nvim-treesitter
|
|
||||||
# installs (~/.local/share/nvim/site/parser/*.so) — and pair each with
|
|
||||||
# highlight queries. Query sources, in priority order:
|
|
||||||
# 1. vendored highlight-queries/*.scm (version-pinned; see the
|
|
||||||
# per-file source headers, MIT),
|
|
||||||
# 2. Neovim's own queries (version-matched to its parsers),
|
|
||||||
# 3. tree-sitter/highlighting from GitHub (cached in the build dir).
|
|
||||||
# The result is embedded as highlight-queries.hpp. Re-run cmake to pick
|
|
||||||
# up grammars installed later.
|
|
||||||
#
|
|
||||||
# Candidate entry points are read from the .so with `nm` rather than
|
|
||||||
# assumed to be tree_sitter_<id>; a missing entry point just makes that
|
|
||||||
# candidate fail at runtime.
|
|
||||||
function(_ts_entry_point out file)
|
function(_ts_entry_point out file)
|
||||||
# OUTPUT_VARIABLE + OUTPUT_QUIET loses the output on CMake 4, so
|
|
||||||
# capture through a temp file.
|
|
||||||
get_filename_component(_ts_nm_base "${file}" NAME)
|
get_filename_component(_ts_nm_base "${file}" NAME)
|
||||||
set(_ts_nm_file "${CMAKE_CURRENT_BINARY_DIR}/ts-entry-${_ts_nm_base}")
|
set(_ts_nm_file "${CMAKE_CURRENT_BINARY_DIR}/ts-entry-${_ts_nm_base}")
|
||||||
execute_process(
|
execute_process(
|
||||||
@@ -44,8 +20,6 @@ function(_ts_entry_point out file)
|
|||||||
if(_ts_nm_rc EQUAL 0 AND EXISTS "${_ts_nm_file}")
|
if(_ts_nm_rc EQUAL 0 AND EXISTS "${_ts_nm_file}")
|
||||||
file(READ "${_ts_nm_file}" _ts_nm_out)
|
file(READ "${_ts_nm_file}" _ts_nm_out)
|
||||||
file(REMOVE "${_ts_nm_file}" "${_ts_nm_file}.err")
|
file(REMOVE "${_ts_nm_file}" "${_ts_nm_file}.err")
|
||||||
# The library also exports the external scanner functions; the
|
|
||||||
# entry point is the one without the _external suffix.
|
|
||||||
string(REGEX MATCHALL " T tree_sitter_[A-Za-z0-9_]+" _ts_syms "${_ts_nm_out}")
|
string(REGEX MATCHALL " T tree_sitter_[A-Za-z0-9_]+" _ts_syms "${_ts_nm_out}")
|
||||||
foreach(_ts_s IN LISTS _ts_syms)
|
foreach(_ts_s IN LISTS _ts_syms)
|
||||||
string(REPLACE " T " "" _ts_s "${_ts_s}")
|
string(REPLACE " T " "" _ts_s "${_ts_s}")
|
||||||
@@ -58,22 +32,11 @@ function(_ts_entry_point out file)
|
|||||||
set(${out} "${_ts_sym}" PARENT_SCOPE)
|
set(${out} "${_ts_sym}" PARENT_SCOPE)
|
||||||
endfunction()
|
endfunction()
|
||||||
|
|
||||||
# Append a query text to <files> (PARENT_SCOPE) unless it duplicates a
|
|
||||||
# hash in <hashes>. The text is written to the build tree right away:
|
|
||||||
# the s-expression `;` comments would split CMake list items and the
|
|
||||||
# query `(` `)` break bracket arguments, so query text only ever lives
|
|
||||||
# in variables and files, never in lists.
|
|
||||||
# Expand Neovim's "; inherits:" directives by appending the inherited
|
|
||||||
# query set's highlights file (recursively; a visited set prevents
|
|
||||||
# cycles). Several languages are stubs that inherit the real query
|
|
||||||
# (html inherits html_tags, qmljs inherits ecma, ...).
|
|
||||||
function(_ts_expand_inherits query_dir text outVar)
|
function(_ts_expand_inherits query_dir text outVar)
|
||||||
set(result "${text}")
|
set(result "${text}")
|
||||||
set(_visited "")
|
set(_visited "")
|
||||||
set(_depth 0)
|
set(_depth 0)
|
||||||
while(_depth LESS 8)
|
while(_depth LESS 8)
|
||||||
# Do not match the leading `;`: a MATCHALL result that itself
|
|
||||||
# contains a semicolon is re-split into list items.
|
|
||||||
string(REGEX MATCHALL "inherits:[ \t]*[A-Za-z0-9_]+" _inh "${result}")
|
string(REGEX MATCHALL "inherits:[ \t]*[A-Za-z0-9_]+" _inh "${result}")
|
||||||
if(NOT _inh)
|
if(NOT _inh)
|
||||||
break()
|
break()
|
||||||
@@ -99,7 +62,6 @@ function(_ts_expand_inherits query_dir text outVar)
|
|||||||
endfunction()
|
endfunction()
|
||||||
|
|
||||||
function(_ts_add_query sid text filesVar hashesVar)
|
function(_ts_add_query sid text filesVar hashesVar)
|
||||||
# filesVar/hashesVar hold the caller's variable names.
|
|
||||||
set(files "${${filesVar}}")
|
set(files "${${filesVar}}")
|
||||||
set(hashes "${${hashesVar}}")
|
set(hashes "${${hashesVar}}")
|
||||||
string(SHA256 _ts_qh "${text}")
|
string(SHA256 _ts_qh "${text}")
|
||||||
@@ -115,7 +77,7 @@ function(_ts_add_query sid text filesVar hashesVar)
|
|||||||
set(${hashesVar} "${hashes}" PARENT_SCOPE)
|
set(${hashesVar} "${hashes}" PARENT_SCOPE)
|
||||||
endfunction()
|
endfunction()
|
||||||
|
|
||||||
set(_ts_candidates "") # entries: <id>|<cmake-safe id>|<lib>|<symbol>
|
set(_ts_candidates "")
|
||||||
file(GLOB _ts_sys_files
|
file(GLOB _ts_sys_files
|
||||||
"/usr/lib/libtree-sitter-*.so" "/usr/local/lib/libtree-sitter-*.so")
|
"/usr/lib/libtree-sitter-*.so" "/usr/local/lib/libtree-sitter-*.so")
|
||||||
foreach(_ts_file IN LISTS _ts_sys_files)
|
foreach(_ts_file IN LISTS _ts_sys_files)
|
||||||
@@ -164,20 +126,13 @@ set(_ts_vendored
|
|||||||
foreach(_ts_id IN LISTS _ts_ids)
|
foreach(_ts_id IN LISTS _ts_ids)
|
||||||
string(REPLACE "-" "_" _ts_sid "${_ts_id}")
|
string(REPLACE "-" "_" _ts_sid "${_ts_id}")
|
||||||
|
|
||||||
# Query candidates in priority order (deduped; identical texts are
|
|
||||||
# skipped, the nvim site and plugin copies are usually the same
|
|
||||||
# file).
|
|
||||||
set(_ts_qfiles "")
|
set(_ts_qfiles "")
|
||||||
set(_ts_qhashes "")
|
set(_ts_qhashes "")
|
||||||
if(_ts_id STREQUAL "cpp")
|
if(_ts_id STREQUAL "cpp")
|
||||||
# The C++ grammar is a superset of C and its query only covers
|
|
||||||
# the C++ delta; base C coverage comes from the C query.
|
|
||||||
file(READ "${CMAKE_CURRENT_SOURCE_DIR}/highlight-queries/c.scm" _ts_qa)
|
file(READ "${CMAKE_CURRENT_SOURCE_DIR}/highlight-queries/c.scm" _ts_qa)
|
||||||
file(READ "${CMAKE_CURRENT_SOURCE_DIR}/highlight-queries/cpp.scm" _ts_qb)
|
file(READ "${CMAKE_CURRENT_SOURCE_DIR}/highlight-queries/cpp.scm" _ts_qb)
|
||||||
_ts_add_query(${_ts_sid} "${_ts_qa}\n${_ts_qb}" _ts_qfiles _ts_qhashes)
|
_ts_add_query(${_ts_sid} "${_ts_qa}\n${_ts_qb}" _ts_qfiles _ts_qhashes)
|
||||||
elseif(_ts_id STREQUAL "typescript" OR _ts_id STREQUAL "tsx")
|
elseif(_ts_id STREQUAL "typescript" OR _ts_id STREQUAL "tsx")
|
||||||
# The TS grammars reuse the JS node names; the JS query usually
|
|
||||||
# compiles against them and gives full coverage.
|
|
||||||
file(READ "${CMAKE_CURRENT_SOURCE_DIR}/highlight-queries/javascript.scm" _ts_qa)
|
file(READ "${CMAKE_CURRENT_SOURCE_DIR}/highlight-queries/javascript.scm" _ts_qa)
|
||||||
file(READ "${CMAKE_CURRENT_SOURCE_DIR}/highlight-queries/typescript.scm" _ts_qb)
|
file(READ "${CMAKE_CURRENT_SOURCE_DIR}/highlight-queries/typescript.scm" _ts_qb)
|
||||||
_ts_add_query(${_ts_sid} "${_ts_qa}\n${_ts_qb}" _ts_qfiles _ts_qhashes)
|
_ts_add_query(${_ts_sid} "${_ts_qa}\n${_ts_qb}" _ts_qfiles _ts_qhashes)
|
||||||
@@ -195,10 +150,6 @@ foreach(_ts_id IN LISTS _ts_ids)
|
|||||||
endif()
|
endif()
|
||||||
endforeach()
|
endforeach()
|
||||||
if(NOT _ts_qfiles)
|
if(NOT _ts_qfiles)
|
||||||
# Last resort: fetch from the tree-sitter/highlighting repo.
|
|
||||||
# Version-skewed against locally installed grammars, so only
|
|
||||||
# used when nothing local exists. Cached; offline builds simply
|
|
||||||
# drop the language.
|
|
||||||
set(_ts_dl "${CMAKE_CURRENT_BINARY_DIR}/ts-query-downloads/${_ts_sid}.scm")
|
set(_ts_dl "${CMAKE_CURRENT_BINARY_DIR}/ts-query-downloads/${_ts_sid}.scm")
|
||||||
if(NOT EXISTS "${_ts_dl}")
|
if(NOT EXISTS "${_ts_dl}")
|
||||||
file(DOWNLOAD
|
file(DOWNLOAD
|
||||||
@@ -219,7 +170,6 @@ foreach(_ts_id IN LISTS _ts_ids)
|
|||||||
continue()
|
continue()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# Emit query sources.
|
|
||||||
set(_ts_qn 0)
|
set(_ts_qn 0)
|
||||||
set(_ts_q_ptrs "")
|
set(_ts_q_ptrs "")
|
||||||
foreach(_ts_qfile IN LISTS _ts_qfiles)
|
foreach(_ts_qfile IN LISTS _ts_qfiles)
|
||||||
@@ -232,7 +182,6 @@ foreach(_ts_id IN LISTS _ts_ids)
|
|||||||
string(APPEND _hl_header
|
string(APPEND _hl_header
|
||||||
"inline constexpr const char* const q_${_ts_sid}[] = { ${_ts_q_ptrs} };\n")
|
"inline constexpr const char* const q_${_ts_sid}[] = { ${_ts_q_ptrs} };\n")
|
||||||
|
|
||||||
# Emit library candidates (system package first, then Neovim).
|
|
||||||
string(APPEND _hl_header "inline constexpr Candidate cand_${_ts_sid}[] = {\n")
|
string(APPEND _hl_header "inline constexpr Candidate cand_${_ts_sid}[] = {\n")
|
||||||
set(_ts_nc 0)
|
set(_ts_nc 0)
|
||||||
foreach(_ts_c IN LISTS _ts_candidates)
|
foreach(_ts_c IN LISTS _ts_candidates)
|
||||||
@@ -248,8 +197,7 @@ foreach(_ts_id IN LISTS _ts_ids)
|
|||||||
endforeach()
|
endforeach()
|
||||||
string(APPEND _hl_header "};\n")
|
string(APPEND _hl_header "};\n")
|
||||||
if(_ts_nc EQUAL 0)
|
if(_ts_nc EQUAL 0)
|
||||||
# Queries but no library: pointless, drop the language.
|
string(APPEND _hl_header "")
|
||||||
string(APPEND _hl_header "") # (arrays stay; grammar row is skipped)
|
|
||||||
continue()
|
continue()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
@@ -263,8 +211,6 @@ endforeach()
|
|||||||
string(APPEND _hl_header "};\n}\n")
|
string(APPEND _hl_header "};\n}\n")
|
||||||
file(WRITE "${HIGHLIGHT_QUERIES_HPP}" "${_hl_header}")
|
file(WRITE "${HIGHLIGHT_QUERIES_HPP}" "${_hl_header}")
|
||||||
|
|
||||||
# Embed the vendored Latin Modern fonts (GUST Font License; provenance
|
|
||||||
# in fonts/latinmodern/GUST-FONT-LICENSE.txt) as byte arrays.
|
|
||||||
set(LM_FONTS
|
set(LM_FONTS
|
||||||
lmroman10-regular
|
lmroman10-regular
|
||||||
lmroman10-italic
|
lmroman10-italic
|
||||||
@@ -314,4 +260,3 @@ qml_module(ZShell-llm
|
|||||||
)
|
)
|
||||||
|
|
||||||
target_include_directories(ZShell-llm PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
|
target_include_directories(ZShell-llm PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
|
||||||
target_include_directories(ZShell-llm PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../Config)
|
|
||||||
|
|||||||
@@ -1,12 +1,13 @@
|
|||||||
#include "chat.hpp"
|
#include "chat.hpp"
|
||||||
|
|
||||||
#include "config.hpp"
|
|
||||||
#include "filetool.hpp"
|
#include "filetool.hpp"
|
||||||
#include "llm.hpp"
|
|
||||||
#include "llmclient.hpp"
|
#include "llmclient.hpp"
|
||||||
#include "shelltool.hpp"
|
#include "shelltool.hpp"
|
||||||
#include "webfetchtool.hpp"
|
#include "webfetchtool.hpp"
|
||||||
|
|
||||||
|
#include "config/rootnodes.hpp"
|
||||||
|
#include "config/llm.hpp"
|
||||||
|
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
|
|
||||||
namespace ZShell::llm {
|
namespace ZShell::llm {
|
||||||
@@ -15,14 +16,12 @@ Chat::Chat(QObject* parent)
|
|||||||
: QObject(parent)
|
: QObject(parent)
|
||||||
, m_store(new ChatStore(this))
|
, m_store(new ChatStore(this))
|
||||||
, m_client(new LlmClient(this)) {
|
, m_client(new LlmClient(this)) {
|
||||||
if (!config::Config::instance()) new config::Config();
|
|
||||||
|
|
||||||
m_store->setLlmClient(m_client);
|
m_store->setLlmClient(m_client);
|
||||||
m_client->tools()->registerTool(new WebFetchTool(m_client->tools()));
|
m_client->tools()->registerTool(new WebFetchTool(m_client->tools()));
|
||||||
m_client->tools()->registerTool(new FileReadTool(m_client->tools()));
|
m_client->tools()->registerTool(new FileReadTool(m_client->tools()));
|
||||||
m_client->tools()->registerTool(new ShellTool(m_client, m_client->tools()));
|
m_client->tools()->registerTool(new ShellTool(m_client, m_client->tools()));
|
||||||
|
|
||||||
const auto* llm = config::Config::instance()->llm();
|
const auto* llm = config::ConfigSingleton::instance()->llm();
|
||||||
m_client->setEndpoint(llm->endpoint());
|
m_client->setEndpoint(llm->endpoint());
|
||||||
m_client->setModel(llm->model());
|
m_client->setModel(llm->model());
|
||||||
m_client->setTemperature(llm->temperature());
|
m_client->setTemperature(llm->temperature());
|
||||||
@@ -144,7 +143,7 @@ bool Chat::toolsEnabled() const {
|
|||||||
|
|
||||||
void Chat::setToolsEnabled(bool value) {
|
void Chat::setToolsEnabled(bool value) {
|
||||||
m_client->setToolsEnabled(value);
|
m_client->setToolsEnabled(value);
|
||||||
if (auto* config = config::Config::instance())
|
if (auto* config = config::ConfigSingleton::instance())
|
||||||
config->llm()->set_tools(value);
|
config->llm()->set_tools(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -154,7 +153,7 @@ bool Chat::sandboxEnabled() const {
|
|||||||
|
|
||||||
void Chat::setSandboxEnabled(bool value) {
|
void Chat::setSandboxEnabled(bool value) {
|
||||||
m_client->setSandboxEnabled(value);
|
m_client->setSandboxEnabled(value);
|
||||||
if (auto* config = config::Config::instance())
|
if (auto* config = config::ConfigSingleton::instance())
|
||||||
config->llm()->set_sandbox(value);
|
config->llm()->set_sandbox(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -195,7 +194,8 @@ void Chat::refreshFromServer() {
|
|||||||
void Chat::selectModel(const QString& id) {
|
void Chat::selectModel(const QString& id) {
|
||||||
if (id.isEmpty()) return;
|
if (id.isEmpty()) return;
|
||||||
m_client->setModel(id);
|
m_client->setModel(id);
|
||||||
if (auto* config = config::Config::instance()) config->llm()->set_model(id);
|
if (auto* config = config::ConfigSingleton::instance())
|
||||||
|
config->llm()->set_model(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace ZShell::llm
|
} // namespace ZShell::llm
|
||||||
|
|||||||
Reference in New Issue
Block a user