mirror of
https://github.com/enso-org/enso.git
synced 2024-10-05 17:17:50 +03:00
Fix missing dropdowns in constructor subexpressions (#10382)
Fixes #10341 <img width="487" alt="image" src="https://github.com/enso-org/enso/assets/919491/af946c1c-a27f-4ed8-8346-b5098e7d5f08"> Also added a new version of vue devtools that is embedded into the dev app itself, and has much better performance than the browser plugin.
This commit is contained in:
parent
db4f7ab3b5
commit
2f7adb9deb
@ -139,8 +139,8 @@
|
||||
"tsx": "^4.7.1",
|
||||
"typescript": "~5.2.2",
|
||||
"unbzip2-stream": "^1.4.3",
|
||||
"vite": "^4.4.9",
|
||||
"vite-plugin-inspect": "^0.7.38",
|
||||
"vite": "^5.3.1",
|
||||
"vite-plugin-vue-devtools": "7.3.4",
|
||||
"vitest": "^1.3.1",
|
||||
"vue-react-wrapper": "^0.3.1",
|
||||
"vue-tsc": "^1.8.27"
|
||||
|
@ -40,22 +40,24 @@ const staticMethod = {
|
||||
}
|
||||
|
||||
test.each`
|
||||
code | callSuggestion | subjectSpan | selfSpan | subjectType | methodName
|
||||
code | callSuggestion | subjectSpan | attachedSpan | subjectType | methodName
|
||||
${'val1.method val2'} | ${method} | ${[0, 4]} | ${[0, 4]} | ${'local.Project.Type'} | ${'.method'}
|
||||
${'local.Project.Type.method val1 val2'} | ${method} | ${[0, 18]} | ${[26, 30]} | ${'local.Project.Type.type'} | ${'.method'}
|
||||
${'Type.method val1'} | ${method} | ${[0, 4]} | ${[12, 16]} | ${'local.Project.Type.type'} | ${'.method'}
|
||||
${'local.Project.Type.method'} | ${method} | ${[0, 18]} | ${[0, 18]} | ${'local.Project.Type.type'} | ${'.method'}
|
||||
${'local.Project.Type.method'} | ${method} | ${[0, 18]} | ${null} | ${'local.Project.Type.type'} | ${'.method'}
|
||||
${'foo.method'} | ${method} | ${[0, 3]} | ${null} | ${'local.Project.Type.type'} | ${'.method'}
|
||||
${'foo.method'} | ${method} | ${[0, 3]} | ${[0, 3]} | ${'local.Project.Type'} | ${'.method'}
|
||||
${'local.Project.Type.static_method val1'} | ${staticMethod} | ${[0, 18]} | ${[0, 18]} | ${'local.Project.Type.type'} | ${'.static_method'}
|
||||
${'Type.Con val1'} | ${con} | ${[0, 4]} | ${[0, 4]} | ${'local.Project.Type.type'} | ${'.Con'}
|
||||
${'..Con val1'} | ${con} | ${null} | ${null} | ${null} | ${'.Con'}
|
||||
${'local.Project.module_method val1'} | ${moduleMethod} | ${[0, 13]} | ${[0, 13]} | ${'local.Project'} | ${'.module_method'}
|
||||
`(
|
||||
'Visualization config for $code',
|
||||
({ code, callSuggestion, subjectSpan, selfSpan, subjectType, methodName }) => {
|
||||
({ code, callSuggestion, subjectSpan, attachedSpan, subjectType, methodName }) => {
|
||||
const spans = {
|
||||
entireFunction: [0, code.length] as [number, number],
|
||||
...(subjectSpan != null ? { subject: subjectSpan as [number, number] } : {}),
|
||||
...(selfSpan != null ? { self: selfSpan as [number, number] } : {}),
|
||||
...(attachedSpan != null ? { attached: attachedSpan as [number, number] } : {}),
|
||||
}
|
||||
const { ast, eid, id } = parseWithSpans(code, spans)
|
||||
const line = ast.lines[0]?.expression
|
||||
@ -101,10 +103,11 @@ test.each`
|
||||
if (typeof visConfig.value.expression === 'string') {
|
||||
expect(visConfig.value.expressionId).toBe(eid('entireFunction'))
|
||||
expect(visConfig.value.expression).toBe(
|
||||
`_ -> ${WIDGETS_ENSO_MODULE}.${GET_WIDGETS_METHOD} ${callSuggestion.definedIn}`,
|
||||
`_ -> ${WIDGETS_ENSO_MODULE}.${GET_WIDGETS_METHOD} ${callSuggestion.memberOf}`,
|
||||
)
|
||||
expect(eid('attached')).toBeUndefined()
|
||||
} else {
|
||||
expect(visConfig.value.expressionId).toBe(eid('self'))
|
||||
expect(visConfig.value.expressionId).toBe(eid('attached'))
|
||||
}
|
||||
expect(visConfig.value.positionalArgumentsExpressions![0]).toBe(methodName)
|
||||
expect(visConfig.value.positionalArgumentsExpressions![1]).toBe("['arg']")
|
||||
|
@ -38,13 +38,8 @@ export function useWidgetFunctionCallInfo(
|
||||
useVisualizationData(config: Ref<Opt<NodeVisualizationConfiguration>>): Ref<Result<any> | null>
|
||||
},
|
||||
) {
|
||||
const methodCallInfo = computed(() => {
|
||||
return getMethodCallInfoRecursively(toValue(input).value, graphDb)
|
||||
})
|
||||
|
||||
const interpreted = computed(() => {
|
||||
return interpretCall(toValue(input).value, methodCallInfo.value == null)
|
||||
})
|
||||
const methodCallInfo = computed(() => getMethodCallInfoRecursively(toValue(input).value, graphDb))
|
||||
const interpreted = computed(() => interpretCall(toValue(input).value))
|
||||
|
||||
const subjectInfo = computed(() => {
|
||||
const analyzed = interpreted.value
|
||||
@ -60,22 +55,31 @@ export function useWidgetFunctionCallInfo(
|
||||
return funcType != null && subjectInfo.value?.typename !== `${funcType}.type`
|
||||
})
|
||||
|
||||
const selfArgumentExternalId = computed<Opt<ExternalId>>(() => {
|
||||
const widgetQuerySubjectExpressionId = computed<Opt<ExternalId>>(() => {
|
||||
const analyzed = interpreted.value
|
||||
if (analyzed.kind === 'infix') {
|
||||
return analyzed.lhs?.externalId
|
||||
} else if (methodCallInfo.value?.suggestion.selfType != null) {
|
||||
const knownArguments = methodCallInfo.value?.suggestion?.arguments
|
||||
const hasSelfArgument = knownArguments?.[0]?.name === 'self'
|
||||
const selfArgument =
|
||||
hasSelfArgument && !selfArgumentPreapplied.value ?
|
||||
analyzed.args.find((a) => a.argName === 'self' || a.argName == null)?.argument
|
||||
: getAccessOprSubject(analyzed.func) ?? analyzed.args[0]?.argument
|
||||
|
||||
return selfArgument?.externalId
|
||||
} else {
|
||||
return null
|
||||
}
|
||||
const knownArguments = methodCallInfo.value?.suggestion?.arguments
|
||||
const hasKnownSelfArgument = knownArguments?.[0]?.name === 'self'
|
||||
|
||||
// First we always want to attach the visualization to the `self` argument,
|
||||
// whenever we can find an unambiguous expression for it.
|
||||
if (hasKnownSelfArgument && !selfArgumentPreapplied.value) {
|
||||
return analyzed.args.find((a) => a.argName === 'self' || a.argName == null)?.argument
|
||||
?.externalId
|
||||
}
|
||||
|
||||
// When no `self` argument can be resolved or it is already applied, attach to the access
|
||||
// chain subject. This will correctly handle constructors and most common cases with not
|
||||
// yet resolved methods.
|
||||
const accessSubject = getAccessOprSubject(analyzed.func)
|
||||
if (accessSubject) {
|
||||
return accessSubject.externalId
|
||||
}
|
||||
// In other cases (e.g. autoscoped expression) there is no good existing
|
||||
// expression to attach the visualization to. Fallback to synthetic type-based expression.
|
||||
return null
|
||||
})
|
||||
|
||||
const visualizationConfig = computed<Opt<NodeVisualizationConfiguration>>(() => {
|
||||
@ -84,7 +88,6 @@ export function useWidgetFunctionCallInfo(
|
||||
methodCallInfo.value,
|
||||
)
|
||||
|
||||
const selfArgId = selfArgumentExternalId.value
|
||||
const info = methodCallInfo.value
|
||||
if (!info) return null
|
||||
const annotatedArgs = info.suggestion.annotations
|
||||
@ -95,9 +98,11 @@ export function useWidgetFunctionCallInfo(
|
||||
Ast.Vector.build(annotatedArgs, Ast.TextLiteral.new).code(),
|
||||
Ast.TextLiteral.new(JSON.stringify(args)).code(),
|
||||
]
|
||||
if (selfArgId != null) {
|
||||
|
||||
const expressionId = widgetQuerySubjectExpressionId.value
|
||||
if (expressionId != null) {
|
||||
return {
|
||||
expressionId: selfArgId,
|
||||
expressionId,
|
||||
visualizationModule: WIDGETS_ENSO_MODULE,
|
||||
expression: {
|
||||
module: WIDGETS_ENSO_MODULE,
|
||||
@ -107,12 +112,12 @@ export function useWidgetFunctionCallInfo(
|
||||
positionalArgumentsExpressions,
|
||||
}
|
||||
} else {
|
||||
// In the case when no self argument is present (for example in autoscoped constructor),
|
||||
// we assume that this is a static function call.
|
||||
// In the case when no clear subject expression exists (for example in autoscoped constructor),
|
||||
// we assume that this is a static function call and create the subject by using resolved type name.
|
||||
return {
|
||||
expressionId: toValue(input).value.externalId,
|
||||
visualizationModule: WIDGETS_ENSO_MODULE,
|
||||
expression: `_ -> ${WIDGETS_ENSO_MODULE}.${GET_WIDGETS_METHOD} ${info.suggestion.definedIn}`,
|
||||
expression: `_ -> ${WIDGETS_ENSO_MODULE}.${GET_WIDGETS_METHOD} ${info.suggestion.memberOf ?? info.suggestion.definedIn}`,
|
||||
positionalArgumentsExpressions,
|
||||
}
|
||||
}
|
||||
|
@ -73,7 +73,7 @@ export interface DropdownEntry {
|
||||
|
||||
<template>
|
||||
<div class="DropdownWidget" :style="styleVars">
|
||||
<ul class="list scrollable" @wheel.stop>
|
||||
<ul class="list scrollable" @wheel.stop.passive>
|
||||
<li
|
||||
v-for="entry in sortedValues"
|
||||
:key="entry.value"
|
||||
|
@ -157,8 +157,8 @@ interface FoundApplication {
|
||||
argName: string | undefined
|
||||
}
|
||||
|
||||
export function interpretCall(callRoot: Ast.Ast, allowInterpretAsInfix: boolean): InterpretedCall {
|
||||
if (allowInterpretAsInfix && callRoot instanceof Ast.OprApp) {
|
||||
export function interpretCall(callRoot: Ast.Ast): InterpretedCall {
|
||||
if (callRoot instanceof Ast.OprApp) {
|
||||
// Infix chains are handled one level at a time. Each application may have at most 2 arguments.
|
||||
return {
|
||||
kind: 'infix',
|
||||
|
@ -8,6 +8,7 @@ import postcssNesting from 'postcss-nesting'
|
||||
import tailwindcss from 'tailwindcss'
|
||||
import tailwindcssNesting from 'tailwindcss/nesting'
|
||||
import { defineConfig, type Plugin } from 'vite'
|
||||
import VueDevTools from 'vite-plugin-vue-devtools'
|
||||
// @ts-expect-error
|
||||
import * as tailwindConfig from 'enso-dashboard/tailwind.config'
|
||||
import { createGatewayServer } from './ydoc-server'
|
||||
@ -27,6 +28,7 @@ export default defineConfig({
|
||||
publicDir: fileURLToPath(new URL('./public', import.meta.url)),
|
||||
envDir: fileURLToPath(new URL('.', import.meta.url)),
|
||||
plugins: [
|
||||
VueDevTools(),
|
||||
vue(),
|
||||
react({
|
||||
include: fileURLToPath(new URL('../ide-desktop/lib/dashboard/**/*.tsx', import.meta.url)),
|
||||
|
@ -44,7 +44,7 @@
|
||||
"sharp": "^0.31.2",
|
||||
"to-ico": "^1.1.5",
|
||||
"tsx": "^4.7.1",
|
||||
"vite": "^5.1.4"
|
||||
"vite": "^5.3.1"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@esbuild/darwin-x64": "^0.17.15",
|
||||
|
@ -95,7 +95,7 @@
|
||||
"tailwindcss-react-aria-components": "^1.1.1",
|
||||
"ts-plugin-namespace-auto-import": "^1.0.0",
|
||||
"typescript": "~5.2.2",
|
||||
"vite": "^4.4.9",
|
||||
"vite": "^5.3.1",
|
||||
"vitest": "^1.3.1"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
|
2549
package-lock.json
generated
2549
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user