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`
defValue: Utils.simplifyExpression(obj[propertyName].toEditableString())
self: obj.name
variables: propertyType.variables
onChanged: function(newExpr) {
if(obj[propertyName].toString() != newExpr.toString()) {
history.addToHistory(new HistoryLib.EditedProperty(
@ -267,7 +268,7 @@ Repeater {
return commentComponent
else if(propertyType == 'boolean')
return checkboxComponent
else if(propertyType == 'Expression')
else if(paramTypeIn(propertyType, ['Expression']))
return expressionEditorComponent
else if(paramTypeIn(propertyType, textTypes))
return textEditorComponent

View file

@ -33,6 +33,11 @@ ListView {
Start index of the first element in this list compared to the global autocompletion index.
*/
property int itemStartIndex: 0
/*!
\qmlproperty int AutocompletionCategory::itemSelected
The global autocompletion index.
*/
property int itemSelected: 0
/*!
\qmlproperty string AutocompletionCategory::category
@ -49,9 +54,9 @@ ListView {
/*!
\qmlproperty var AutocompletionCategory::autocompleteGenerator
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
@ -60,7 +65,7 @@ ListView {
property string baseText: ""
width: parent.width
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) : []
header: Column {
@ -82,10 +87,10 @@ ListView {
}
delegate: Rectangle {
property bool selected: index + listFiltered.itemStartIndex == acPopupContent.itemSelected
property bool selected: index + listFiltered.itemStartIndex == listFiltered.itemSelected
width: autocompleteText.width
height: autocompleteText.height
width: listFiltered.width
height: Math.max(autocompleteText.height, annotationText.height)
color: selected ? sysPalette.highlight : 'transparent'
Text {
@ -94,8 +99,17 @@ ListView {
bottomPadding: 2
leftPadding: 15
text: listFiltered.model[index].text
width: listFiltered.width
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.
*/
property string self: ""
/*!
\qmlproperty var ExpressionEditor::variables
Accepted variables for the expression.
*/
property var variables: []
/*!
\qmlproperty string ExpressionEditor::placeholderText
Value of the editor.
@ -250,8 +255,8 @@ Item {
visible: currentToken != null && identifierTokenTypes.includes(currentToken.type)
// Focus handling.
readonly property var lists: [constantsList, functionsList, executableObjectList]
readonly property int itemCount: constantsList.model.length + functionsList.model.length + executableObjectList.model.length
readonly property var lists: [variablesList, constantsList, functionsList, executableObjectsList, objectsList]
readonly property int itemCount: variablesList.model.length, constantsList.model.length + functionsList.model.length + executableObjectsList.model.length + objectsList.model.length
property int itemSelected: 0
/*!
@ -276,40 +281,79 @@ Item {
function autocomplete() {
let autotext = autocompleteAt(itemSelected)
let startPos = currentToken.startPosition
console.log("Autocompleting",autotext.text,startPos)
editor.remove(startPos, startPos+currentToken.value.length)
editor.insert(startPos, autotext.autocomplete)
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 {
id: constantsList
itemStartIndex: 0
category: qsTr("Constants")
itemStartIndex: variablesList.model.length
itemSelected: parent.itemSelected
categoryItems: Parsing.CONSTANTS_LIST
autocompleteGenerator: (item) => {return {'text': item, 'autocomplete': item + " ", 'cursorFinalOffset': 0}}
baseText: parent.currentToken.value
autocompleteGenerator: (item) => {return {
'text': item, 'annotation': '',
'autocomplete': item + " ", 'cursorFinalOffset': 0
}}
baseText: parent.visible ? parent.currentToken.value : ""
}
AutocompletionCategory {
id: functionsList
itemStartIndex: constantsList.model.length
category: qsTr("Functions")
itemStartIndex: variablesList.model.length + constantsList.model.length
itemSelected: parent.itemSelected
categoryItems: Parsing.FUNCTIONS_LIST
autocompleteGenerator: (item) => {return {'text': item, 'autocomplete': item+'()', 'cursorFinalOffset': -1}}
baseText: parent.currentToken.value
autocompleteGenerator: (item) => {return {
'text': item, 'annotation': '',
'autocomplete': item+'()', 'cursorFinalOffset': -1
}}
baseText: parent.visible ? parent.currentToken.value : ""
}
AutocompletionCategory {
id: executableObjectList
id: executableObjectsList
itemStartIndex: constantsList.model.length + functionsList.model.length
category: qsTr("Executable Objects")
categoryItems: Objects.getObjectsName("ExecutableObject")
autocompleteGenerator: (item) => {return {'text': item, 'autocomplete': item+'()', 'cursorFinalOffset': -1}}
baseText: parent.currentToken.value
itemStartIndex: variablesList.model.length + constantsList.model.length + functionsList.model.length
itemSelected: parent.itemSelected
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() {
return [this.targetName, this.targetType, this.targetProperty,
return [this.targetName, this.targetType,
this.previousXValue.toEditableString(), this.newXValue.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.
* If variables with each of the allowedLetters is created, a subscript
* number is added to the name.
* @param {string} prefix - Prefix to the name.
* @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,
// as well as adding a sub number when needs be.
var newid = 0
@ -40,7 +41,7 @@ function getNewName(allowedLetters) {
do {
var letter = allowedLetters[newid % 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
} while(ret in Objects.currentObjectsByName)
return ret
@ -80,10 +81,10 @@ class DrawableObject {
* List of properties used in the Object Editor.
*
* 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
* 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
* 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 displayTypeMultiple(){return qsTr('Functions')}
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','destinationDomain')]: 'Domain',
'comment1': QT_TRANSLATE_NOOP(

View file

@ -35,7 +35,7 @@ class GainBode extends Common.ExecutableObject {
static properties() {return {
[QT_TRANSLATE_NOOP('prop','om_0')]: new P.ObjectType('Point'),
[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','labelX')]: 'number',
[QT_TRANSLATE_NOOP('prop','omGraduation')]: 'boolean'

View file

@ -32,7 +32,7 @@ class PhaseBode extends Common.ExecutableObject {
static displayTypeMultiple(){return qsTr('Bode Phases')}
static properties() {return {
[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','labelPosition')]: P.Enum.Position,
[QT_TRANSLATE_NOOP('prop','labelX')]: 'number'

View file

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

View file

@ -26,7 +26,7 @@
.import "../math/latex.js" as Latex
class SommeGainsBode extends Common.DrawableObject {
class SommeGainsBode extends Common.ExecutableObject {
static type(){return 'Somme gains Bode'}
static displayType(){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 displayTypeMultiple(){return qsTr('Texts')}
static properties() {return {
[QT_TRANSLATE_NOOP('prop','x')]: 'Expression',
[QT_TRANSLATE_NOOP('prop','y')]: 'Expression',
[QT_TRANSLATE_NOOP('prop','x')]: new P.Expression(),
[QT_TRANSLATE_NOOP('prop','y')]: new P.Expression(),
[QT_TRANSLATE_NOOP('prop','labelPosition')]: P.Enum.Positioning,
[QT_TRANSLATE_NOOP('prop','text')]: 'string',
'comment1': QT_TRANSLATE_NOOP(

View file

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