Variables & objects (+ their type) in autocompletion.

This commit is contained in:
Ad5001 2022-10-20 01:14:09 +02:00
parent 77ae54fa18
commit 15b87fc15d
Signed by: Ad5001
GPG key ID: 7251B1AF90B960F9
12 changed files with 102 additions and 35 deletions

View file

@ -74,6 +74,7 @@ Repeater {
icon: `settings/custom/${propertyIcon}.svg` icon: `settings/custom/${propertyIcon}.svg`
defValue: Utils.simplifyExpression(obj[propertyName].toEditableString()) defValue: Utils.simplifyExpression(obj[propertyName].toEditableString())
self: obj.name self: obj.name
variables: propertyType.variables
onChanged: function(newExpr) { onChanged: function(newExpr) {
if(obj[propertyName].toString() != newExpr.toString()) { if(obj[propertyName].toString() != newExpr.toString()) {
history.addToHistory(new HistoryLib.EditedProperty( history.addToHistory(new HistoryLib.EditedProperty(
@ -267,7 +268,7 @@ Repeater {
return commentComponent return commentComponent
else if(propertyType == 'boolean') else if(propertyType == 'boolean')
return checkboxComponent return checkboxComponent
else if(propertyType == 'Expression') else if(paramTypeIn(propertyType, ['Expression']))
return expressionEditorComponent return expressionEditorComponent
else if(paramTypeIn(propertyType, textTypes)) else if(paramTypeIn(propertyType, textTypes))
return textEditorComponent return textEditorComponent

View file

@ -33,6 +33,11 @@ ListView {
Start index of the first element in this list compared to the global autocompletion index. Start index of the first element in this list compared to the global autocompletion index.
*/ */
property int itemStartIndex: 0 property int itemStartIndex: 0
/*!
\qmlproperty int AutocompletionCategory::itemSelected
The global autocompletion index.
*/
property int itemSelected: 0
/*! /*!
\qmlproperty string AutocompletionCategory::category \qmlproperty string AutocompletionCategory::category
@ -49,9 +54,9 @@ ListView {
/*! /*!
\qmlproperty var AutocompletionCategory::autocompleteGenerator \qmlproperty var AutocompletionCategory::autocompleteGenerator
Javascript function taking the name of the item to create an autocompletion item (dictionary with Javascript function taking the name of the item to create an autocompletion item (dictionary with
a 'text', 'autocomplete', and 'cursorFinalOffset' keys. a 'text', 'annotation' 'autocomplete', and 'cursorFinalOffset' keys.
*/ */
property var autocompleteGenerator: (item) => {return {'text': item, 'autocomplete': item, 'cursorFinalOffset': 0}} property var autocompleteGenerator: (item) => {return {'text': item, 'autocomplete': item, 'annotation': '', 'cursorFinalOffset': 0}}
/*! /*!
\qmlproperty string AutocompletionCategory::baseText \qmlproperty string AutocompletionCategory::baseText
@ -60,7 +65,7 @@ ListView {
property string baseText: "" property string baseText: ""
width: parent.width width: parent.width
visible: model.length > 0 visible: model.length > 0
implicitHeight: contentItem.childrenRect.height + headerItem.height implicitHeight: contentItem.childrenRect.height
model: parent.visible ? categoryItems.filter((item) => item.includes(baseText)).map(autocompleteGenerator) : [] model: parent.visible ? categoryItems.filter((item) => item.includes(baseText)).map(autocompleteGenerator) : []
header: Column { header: Column {
@ -82,10 +87,10 @@ ListView {
} }
delegate: Rectangle { delegate: Rectangle {
property bool selected: index + listFiltered.itemStartIndex == acPopupContent.itemSelected property bool selected: index + listFiltered.itemStartIndex == listFiltered.itemSelected
width: autocompleteText.width width: listFiltered.width
height: autocompleteText.height height: Math.max(autocompleteText.height, annotationText.height)
color: selected ? sysPalette.highlight : 'transparent' color: selected ? sysPalette.highlight : 'transparent'
Text { Text {
@ -94,8 +99,17 @@ ListView {
bottomPadding: 2 bottomPadding: 2
leftPadding: 15 leftPadding: 15
text: listFiltered.model[index].text text: listFiltered.model[index].text
width: listFiltered.width
color: parent.selected ? sysPalette.highlightedText : sysPalette.windowText color: parent.selected ? sysPalette.highlightedText : sysPalette.windowText
} }
Text {
id: annotationText
anchors.right: parent.right
topPadding: 2
bottomPadding: 2
rightPadding: 15
text: listFiltered.model[index].annotation
color: parent.selected ? sysPaletteIn.highlightedText : sysPaletteIn.windowText
}
} }
} }

View file

@ -61,6 +61,11 @@ Item {
Used to prevent circular dependency. Used to prevent circular dependency.
*/ */
property string self: "" property string self: ""
/*!
\qmlproperty var ExpressionEditor::variables
Accepted variables for the expression.
*/
property var variables: []
/*! /*!
\qmlproperty string ExpressionEditor::placeholderText \qmlproperty string ExpressionEditor::placeholderText
Value of the editor. Value of the editor.
@ -250,8 +255,8 @@ Item {
visible: currentToken != null && identifierTokenTypes.includes(currentToken.type) visible: currentToken != null && identifierTokenTypes.includes(currentToken.type)
// Focus handling. // Focus handling.
readonly property var lists: [constantsList, functionsList, executableObjectList] readonly property var lists: [variablesList, constantsList, functionsList, executableObjectsList, objectsList]
readonly property int itemCount: constantsList.model.length + functionsList.model.length + executableObjectList.model.length readonly property int itemCount: variablesList.model.length, constantsList.model.length + functionsList.model.length + executableObjectsList.model.length + objectsList.model.length
property int itemSelected: 0 property int itemSelected: 0
/*! /*!
@ -276,40 +281,79 @@ Item {
function autocomplete() { function autocomplete() {
let autotext = autocompleteAt(itemSelected) let autotext = autocompleteAt(itemSelected)
let startPos = currentToken.startPosition let startPos = currentToken.startPosition
console.log("Autocompleting",autotext.text,startPos)
editor.remove(startPos, startPos+currentToken.value.length) editor.remove(startPos, startPos+currentToken.value.length)
editor.insert(startPos, autotext.autocomplete) editor.insert(startPos, autotext.autocomplete)
editor.cursorPosition = startPos+autotext.autocomplete.length+autotext.cursorFinalOffset editor.cursorPosition = startPos+autotext.autocomplete.length+autotext.cursorFinalOffset
} }
AutocompletionCategory {
id: variablesList
category: qsTr("Variables")
itemStartIndex: 0
itemSelected: parent.itemSelected
categoryItems: control.variables
autocompleteGenerator: (item) => {return {
'text': item, 'annotation': '',
'autocomplete': item + " ", 'cursorFinalOffset': 0
}}
baseText: parent.visible ? parent.currentToken.value : ""
}
AutocompletionCategory { AutocompletionCategory {
id: constantsList id: constantsList
itemStartIndex: 0
category: qsTr("Constants") category: qsTr("Constants")
itemStartIndex: variablesList.model.length
itemSelected: parent.itemSelected
categoryItems: Parsing.CONSTANTS_LIST categoryItems: Parsing.CONSTANTS_LIST
autocompleteGenerator: (item) => {return {'text': item, 'autocomplete': item + " ", 'cursorFinalOffset': 0}} autocompleteGenerator: (item) => {return {
baseText: parent.currentToken.value 'text': item, 'annotation': '',
'autocomplete': item + " ", 'cursorFinalOffset': 0
}}
baseText: parent.visible ? parent.currentToken.value : ""
} }
AutocompletionCategory { AutocompletionCategory {
id: functionsList id: functionsList
itemStartIndex: constantsList.model.length
category: qsTr("Functions") category: qsTr("Functions")
itemStartIndex: variablesList.model.length + constantsList.model.length
itemSelected: parent.itemSelected
categoryItems: Parsing.FUNCTIONS_LIST categoryItems: Parsing.FUNCTIONS_LIST
autocompleteGenerator: (item) => {return {'text': item, 'autocomplete': item+'()', 'cursorFinalOffset': -1}} autocompleteGenerator: (item) => {return {
baseText: parent.currentToken.value 'text': item, 'annotation': '',
'autocomplete': item+'()', 'cursorFinalOffset': -1
}}
baseText: parent.visible ? parent.currentToken.value : ""
} }
AutocompletionCategory { AutocompletionCategory {
id: executableObjectList id: executableObjectsList
itemStartIndex: constantsList.model.length + functionsList.model.length
category: qsTr("Executable Objects") category: qsTr("Executable Objects")
categoryItems: Objects.getObjectsName("ExecutableObject") itemStartIndex: variablesList.model.length + constantsList.model.length + functionsList.model.length
autocompleteGenerator: (item) => {return {'text': item, 'autocomplete': item+'()', 'cursorFinalOffset': -1}} itemSelected: parent.itemSelected
baseText: parent.currentToken.value categoryItems: Objects.getObjectsName("ExecutableObject").filter(obj => obj != self)
autocompleteGenerator: (item) => {return {
'text': item, 'annotation': `${Objects.currentObjectsByName[item].constructor.displayType()}`,
'autocomplete': item+'()', 'cursorFinalOffset': -1
}}
baseText: parent.visible ? parent.currentToken.value : ""
}
AutocompletionCategory {
id: objectsList
category: qsTr("Objects")
itemStartIndex: executableObjectsList.model.length + variablesList.model.length + constantsList.model.length + functionsList.model.length
itemSelected: parent.itemSelected
categoryItems: Object.keys(Objects.currentObjectsByName).filter(obj => obj != self)
autocompleteGenerator: (item) => {return {
'text': item, 'annotation': `${Objects.currentObjectsByName[item].constructor.displayType()}`,
'autocomplete': item+'.', 'cursorFinalOffset': 0
}}
baseText: parent.visible ? parent.currentToken.value : ""
} }
} }
} }

View file

@ -75,7 +75,7 @@ class EditedPosition extends C.Action {
} }
export() { export() {
return [this.targetName, this.targetType, this.targetProperty, return [this.targetName, this.targetType,
this.previousXValue.toEditableString(), this.newXValue.toEditableString(), this.previousXValue.toEditableString(), this.newXValue.toEditableString(),
this.previousYValue.toEditableString(), this.newYValue.toEditableString()] this.previousYValue.toEditableString(), this.newYValue.toEditableString()]
} }

View file

@ -30,9 +30,10 @@
* Creates a new name for an object, based on the \c allowedLetters. * Creates a new name for an object, based on the \c allowedLetters.
* If variables with each of the allowedLetters is created, a subscript * If variables with each of the allowedLetters is created, a subscript
* number is added to the name. * number is added to the name.
* @param {string} prefix - Prefix to the name.
* @return {string} New unused name for a new object. * @return {string} New unused name for a new object.
*/ */
function getNewName(allowedLetters) { function getNewName(allowedLetters, prefix='') {
// Allows to get a new name, based on the allowed letters, // Allows to get a new name, based on the allowed letters,
// as well as adding a sub number when needs be. // as well as adding a sub number when needs be.
var newid = 0 var newid = 0
@ -40,7 +41,7 @@ function getNewName(allowedLetters) {
do { do {
var letter = allowedLetters[newid % allowedLetters.length] var letter = allowedLetters[newid % allowedLetters.length]
var num = Math.floor((newid - (newid % allowedLetters.length)) / allowedLetters.length) var num = Math.floor((newid - (newid % allowedLetters.length)) / allowedLetters.length)
ret = letter + (num > 0 ? Utils.textsub(num-1) : '') ret = prefix + letter + (num > 0 ? Utils.textsub(num-1) : '')
newid += 1 newid += 1
} while(ret in Objects.currentObjectsByName) } while(ret in Objects.currentObjectsByName)
return ret return ret
@ -80,10 +81,10 @@ class DrawableObject {
* List of properties used in the Object Editor. * List of properties used in the Object Editor.
* *
* Properties are set with key as property name and * Properties are set with key as property name and
* value as it's type name (e.g 'Expression', 'string'...), * value as it's type name (e.g 'numbers', 'string'...),
* an Enum for enumerations, an ObjectType for DrawableObjects * an Enum for enumerations, an ObjectType for DrawableObjects
* with a specific type, a List instance for lists, a * with a specific type, a List instance for lists, a
* Dictionary instance for dictionaries... * Dictionary instance for dictionaries, an Expression for expressions...
* *
* If the property is to be translated, the key should be passed * If the property is to be translated, the key should be passed
* through the QT_TRANSLATE_NOOP macro in that form: * through the QT_TRANSLATE_NOOP macro in that form:

View file

@ -30,7 +30,7 @@ class Function extends Common.ExecutableObject {
static displayType(){return qsTr('Function')} static displayType(){return qsTr('Function')}
static displayTypeMultiple(){return qsTr('Functions')} static displayTypeMultiple(){return qsTr('Functions')}
static properties() {return { static properties() {return {
[QT_TRANSLATE_NOOP('prop','expression')]: 'Expression', [QT_TRANSLATE_NOOP('prop','expression')]: new P.Expression('x'),
[QT_TRANSLATE_NOOP('prop','definitionDomain')]: 'Domain', [QT_TRANSLATE_NOOP('prop','definitionDomain')]: 'Domain',
[QT_TRANSLATE_NOOP('prop','destinationDomain')]: 'Domain', [QT_TRANSLATE_NOOP('prop','destinationDomain')]: 'Domain',
'comment1': QT_TRANSLATE_NOOP( 'comment1': QT_TRANSLATE_NOOP(

View file

@ -35,7 +35,7 @@ class GainBode extends Common.ExecutableObject {
static properties() {return { static properties() {return {
[QT_TRANSLATE_NOOP('prop','om_0')]: new P.ObjectType('Point'), [QT_TRANSLATE_NOOP('prop','om_0')]: new P.ObjectType('Point'),
[QT_TRANSLATE_NOOP('prop','pass')]: P.Enum.BodePass, [QT_TRANSLATE_NOOP('prop','pass')]: P.Enum.BodePass,
[QT_TRANSLATE_NOOP('prop','gain')]: 'Expression', [QT_TRANSLATE_NOOP('prop','gain')]: new P.Expression(),
[QT_TRANSLATE_NOOP('prop','labelPosition')]: P.Enum.Position, [QT_TRANSLATE_NOOP('prop','labelPosition')]: P.Enum.Position,
[QT_TRANSLATE_NOOP('prop','labelX')]: 'number', [QT_TRANSLATE_NOOP('prop','labelX')]: 'number',
[QT_TRANSLATE_NOOP('prop','omGraduation')]: 'boolean' [QT_TRANSLATE_NOOP('prop','omGraduation')]: 'boolean'

View file

@ -32,7 +32,7 @@ class PhaseBode extends Common.ExecutableObject {
static displayTypeMultiple(){return qsTr('Bode Phases')} static displayTypeMultiple(){return qsTr('Bode Phases')}
static properties() {return { static properties() {return {
[QT_TRANSLATE_NOOP('prop','om_0')]: new P.ObjectType('Point'), [QT_TRANSLATE_NOOP('prop','om_0')]: new P.ObjectType('Point'),
[QT_TRANSLATE_NOOP('prop','phase')]: 'Expression', [QT_TRANSLATE_NOOP('prop','phase')]: new P.Expression(),
[QT_TRANSLATE_NOOP('prop','unit')]: new P.Enum('°', 'deg', 'rad'), [QT_TRANSLATE_NOOP('prop','unit')]: new P.Enum('°', 'deg', 'rad'),
[QT_TRANSLATE_NOOP('prop','labelPosition')]: P.Enum.Position, [QT_TRANSLATE_NOOP('prop','labelPosition')]: P.Enum.Position,
[QT_TRANSLATE_NOOP('prop','labelX')]: 'number' [QT_TRANSLATE_NOOP('prop','labelX')]: 'number'

View file

@ -30,8 +30,8 @@ class Point extends Common.DrawableObject {
static displayTypeMultiple(){return qsTr('Points')} static displayTypeMultiple(){return qsTr('Points')}
static properties() {return { static properties() {return {
[QT_TRANSLATE_NOOP('prop','x')]: 'Expression', [QT_TRANSLATE_NOOP('prop','x')]: new P.Expression(),
[QT_TRANSLATE_NOOP('prop','y')]: 'Expression', [QT_TRANSLATE_NOOP('prop','y')]: new P.Expression(),
[QT_TRANSLATE_NOOP('prop','labelPosition')]: P.Enum.Position, [QT_TRANSLATE_NOOP('prop','labelPosition')]: P.Enum.Position,
[QT_TRANSLATE_NOOP('prop','pointStyle')]: new P.Enum('●', '✕', '') [QT_TRANSLATE_NOOP('prop','pointStyle')]: new P.Enum('●', '✕', '')
}} }}

View file

@ -26,7 +26,7 @@
.import "../math/latex.js" as Latex .import "../math/latex.js" as Latex
class SommeGainsBode extends Common.DrawableObject { class SommeGainsBode extends Common.ExecutableObject {
static type(){return 'Somme gains Bode'} static type(){return 'Somme gains Bode'}
static displayType(){return qsTr('Bode Magnitudes Sum')} static displayType(){return qsTr('Bode Magnitudes Sum')}
static displayTypeMultiple(){return qsTr('Bode Magnitudes Sum')} static displayTypeMultiple(){return qsTr('Bode Magnitudes Sum')}

View file

@ -30,8 +30,8 @@ class Text extends Common.DrawableObject {
static displayType(){return qsTr('Text')} static displayType(){return qsTr('Text')}
static displayTypeMultiple(){return qsTr('Texts')} static displayTypeMultiple(){return qsTr('Texts')}
static properties() {return { static properties() {return {
[QT_TRANSLATE_NOOP('prop','x')]: 'Expression', [QT_TRANSLATE_NOOP('prop','x')]: new P.Expression(),
[QT_TRANSLATE_NOOP('prop','y')]: 'Expression', [QT_TRANSLATE_NOOP('prop','y')]: new P.Expression(),
[QT_TRANSLATE_NOOP('prop','labelPosition')]: P.Enum.Positioning, [QT_TRANSLATE_NOOP('prop','labelPosition')]: P.Enum.Positioning,
[QT_TRANSLATE_NOOP('prop','text')]: 'string', [QT_TRANSLATE_NOOP('prop','text')]: 'string',
'comment1': QT_TRANSLATE_NOOP( 'comment1': QT_TRANSLATE_NOOP(

View file

@ -16,6 +16,13 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
class Expression {
constructor(...variables) {
this.type = 'Expression'
this.variables = variables
}
}
class Enum { class Enum {
constructor(...values) { constructor(...values) {
this.type = 'Enum' this.type = 'Enum'