Skip to content

Commit

Permalink
Refactoring in preparation for normalized qualified names (#11927)
Browse files Browse the repository at this point in the history
* Refactoring in preparation for normalized qualified names

- `SuggestionUpdateProcessor` will simplify adding more contextual information
  to the update application process.
- Mock suggestion data is constructed using `lsUpdate` so that the mocking
  logic doesn't have to be kept consistent with the `lsUpdate` implementation.
- When uploading, use `ExternalId` to identify function; it's simpler than
  comparing stack items.
- Correct some language server definitions that can be `null` in practice.
- Add a test covering *current* behavior wrt. #11815; following PR will update
  expected results.
  • Loading branch information
kazcw authored Jan 2, 2025
1 parent 8054ff7 commit 77ca61f
Show file tree
Hide file tree
Showing 25 changed files with 712 additions and 636 deletions.
2 changes: 1 addition & 1 deletion app/gui/src/project-view/components/CodeEditor/tooltips.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ export function ensoHoverTooltip(
nodeId,
syntax: syn.name,
graphDb: graphStore.db,
suggestionDbStore: suggestionDbStore,
suggestionDbStore,
})
})
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import { expect, test } from 'vitest'

import {
compareSuggestions,
labelOfEntry,
Expand All @@ -14,9 +12,10 @@ import {
makeModule,
makeModuleMethod,
makeStaticMethod,
} from '@/stores/suggestionDatabase/entry'
} from '@/stores/suggestionDatabase/mockSuggestion'
import { allRanges } from '@/util/data/range'
import shuffleSeed from 'shuffle-seed'
import { expect, test } from 'vitest'

test.each([
[makeModuleMethod('Standard.Base.Data.read'), 'Data.read'],
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,16 @@
import { expect, test } from 'vitest'

import { Filtering, type MatchResult } from '@/components/ComponentBrowser/filtering'
import { entryQn, SuggestionEntry } from '@/stores/suggestionDatabase/entry'
import {
entryQn,
makeConstructor,
makeFunction,
makeLocal,
makeMethod,
makeModule,
makeModuleMethod,
makeStaticMethod,
SuggestionEntry,
} from '@/stores/suggestionDatabase/entry'
} from '@/stores/suggestionDatabase/mockSuggestion'
import { qnLastSegment, QualifiedName } from '@/util/qualifiedName'
import { expect, test } from 'vitest'
import { Opt } from 'ydoc-shared/util/data/opt'

test.each([
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@ import {
import { compareOpt } from '@/util/compare'
import { isSome } from '@/util/data/opt'
import { Range } from '@/util/data/range'
import { ANY_TYPE_QN } from '@/util/ensoTypes'
import { displayedIconOf } from '@/util/getIconName'
import type { Icon } from '@/util/iconName'
import type { QualifiedName } from '@/util/qualifiedName'
import { qnLastSegmentIndex, tryQualifiedName } from '@/util/qualifiedName'
import { unwrap } from 'ydoc-shared/util/data/result'

interface ComponentLabelInfo {
label: string
Expand Down Expand Up @@ -109,14 +109,12 @@ export function makeComponent({ id, entry, match }: ComponentInfo): Component {
}
}

const ANY_TYPE = unwrap(tryQualifiedName('Standard.Base.Any.Any'))

/** Create {@link Component} list from filtered suggestions. */
export function makeComponentList(db: SuggestionDb, filtering: Filtering): Component[] {
function* matchSuggestions() {
// All types are descendants of `Any`, so we can safely prepopulate it here.
// This way, we will use it even when `selfArg` is not a valid qualified name.
const additionalSelfTypes: QualifiedName[] = [ANY_TYPE]
const additionalSelfTypes: QualifiedName[] = [ANY_TYPE_QN]
if (filtering.selfArg?.type === 'known') {
const maybeName = tryQualifiedName(filtering.selfArg.typename)
if (maybeName.ok) populateAdditionalSelfTypes(db, additionalSelfTypes, maybeName.value)
Expand All @@ -140,7 +138,7 @@ export function makeComponentList(db: SuggestionDb, filtering: Filtering): Compo
function populateAdditionalSelfTypes(db: SuggestionDb, list: QualifiedName[], name: QualifiedName) {
let entry = db.getEntryByQualifiedName(name)
// We don’t need to add `Any` to the list, because the caller already did that.
while (entry != null && entry.parentType != null && entry.parentType !== ANY_TYPE) {
while (entry != null && entry.parentType != null && entry.parentType !== ANY_TYPE_QN) {
list.push(entry.parentType)
entry = db.getEntryByQualifiedName(entry.parentType)
}
Expand Down
3 changes: 2 additions & 1 deletion app/gui/src/project-view/components/GraphEditor.vue
Original file line number Diff line number Diff line change
Expand Up @@ -580,6 +580,7 @@ async function handleFileDrop(event: DragEvent) {
if (!event.dataTransfer?.items) return
;[...event.dataTransfer.items].forEach(async (item, index) => {
if (item.kind === 'file') {
if (!graphStore.methodAst.ok) return
const file = item.getAsFile()
if (!file) return
const clientPos = new Vec2(event.clientX, event.clientY)
Expand All @@ -591,7 +592,7 @@ async function handleFileDrop(event: DragEvent) {
pos,
projectStore.isOnLocalBackend,
event.shiftKey,
projectStore.executionContext.getStackTop(),
graphStore.methodAst.value.externalId,
)
const uploadResult = await uploader.upload()
if (uploadResult.ok) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,7 @@ import { useProjectStore } from '@/stores/project'
import type { AstId } from '@/util/ast/abstract'
import type { Vec2 } from '@/util/data/vec2'
import { set } from 'lib0'
import { computed, shallowRef, toRaw } from 'vue'
import { stackItemsEqual } from 'ydoc-shared/languageServerTypes'
import { computed, shallowRef } from 'vue'
const emit = defineEmits<{
nodeOutputPortDoubleClick: [portId: AstId]
Expand Down Expand Up @@ -48,9 +47,9 @@ useEvent(window, 'keydown', displacingWithArrows.events.keydown)
const uploadingFiles = computed<[FileName, File][]>(() => {
const uploads = [...projectStore.awareness.allUploads()]
if (uploads.length == 0) return []
const currentStackItem = toRaw(projectStore.executionContext.getStackTop())
return uploads.filter(([, file]) => stackItemsEqual(file.stackItem, currentStackItem))
if (uploads.length == 0 || !graphStore.methodAst.ok) return []
const currentMethod = graphStore.methodAst.value.externalId
return uploads.filter(([, file]) => file.method === currentMethod)
})
const graphNodeSelections = shallowRef<HTMLElement>()
Expand Down
39 changes: 15 additions & 24 deletions app/gui/src/project-view/components/GraphEditor/upload.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@ import { Vec2 } from '@/util/data/vec2'
import type { DataServer } from '@/util/net/dataServer'
import { Keccak, sha3_224 as SHA3 } from '@noble/hashes/sha3'
import type { Hash } from '@noble/hashes/utils'
import { markRaw, toRaw } from 'vue'
import { escapeTextLiteral } from 'ydoc-shared/ast/text'
import type { LanguageServer } from 'ydoc-shared/languageServer'
import type { Path, StackItem, Uuid } from 'ydoc-shared/languageServerTypes'
import type { Path, Uuid } from 'ydoc-shared/languageServerTypes'
import { Err, Ok, type Result } from 'ydoc-shared/util/data/result'
import { type ExternalId } from 'ydoc-shared/yjsModel'

// === Constants ===

Expand Down Expand Up @@ -45,7 +45,6 @@ export interface UploadResult {
export class Uploader {
private checksum: Hash<Keccak>
private uploadedBytes: bigint
private stackItem: StackItem
private awareness: Awareness
private projectFiles: ProjectFiles

Expand All @@ -60,11 +59,10 @@ export class Uploader {
private position: Vec2,
private isOnLocalBackend: boolean,
private disableDirectRead: boolean,
stackItem: StackItem,
private readonly method: ExternalId,
) {
this.checksum = SHA3.create()
this.uploadedBytes = BigInt(0)
this.stackItem = markRaw(toRaw(stackItem))
this.awareness = projectStore.awareness
this.projectFiles = useProjectFiles(projectStore)
}
Expand All @@ -81,16 +79,17 @@ export class Uploader {
position: Vec2,
isOnLocalBackend: boolean,
disableDirectRead: boolean,
stackItem: StackItem,
method: ExternalId,
): Uploader {
return new Uploader(
projectStore,
file,
position,
isOnLocalBackend,
disableDirectRead,
stackItem,
)
return new Uploader(projectStore, file, position, isOnLocalBackend, disableDirectRead, method)
}

private progressUpdate(sizePercentage: number) {
return {
sizePercentage,
position: this.position,
method: this.method,
}
}

/** Start the upload process */
Expand All @@ -111,11 +110,7 @@ export class Uploader {
if (!dataDirExists.ok) return dataDirExists
const name = await this.projectFiles.pickUniqueName(dataDirPath, this.file.name)
if (!name.ok) return name
this.awareness.addOrUpdateUpload(name.value, {
sizePercentage: 0,
position: this.position,
stackItem: this.stackItem,
})
this.awareness.addOrUpdateUpload(name.value, this.progressUpdate(0))
const remotePath: Path = { rootId, segments: [DATA_DIR_NAME, name.value] }
const cleanup = this.cleanup.bind(this, name.value)
const writableStream = new WritableStream<Uint8Array>({
Expand All @@ -131,11 +126,7 @@ export class Uploader {
this.uploadedBytes += BigInt(chunk.length)
const bytes = Number(this.uploadedBytes)
const sizePercentage = Math.round((bytes / this.file.size) * 100)
this.awareness.addOrUpdateUpload(name.value, {
sizePercentage,
position: this.position,
stackItem: this.stackItem,
})
this.awareness.addOrUpdateUpload(name.value, this.progressUpdate(sizePercentage))
},
close: cleanup,
abort: async (reason: string) => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import { WidgetInput } from '@/providers/widgetRegistry'
import { parseWithSpans } from '@/stores/graph/__tests__/graphDatabase.test'
import type { NodeVisualizationConfiguration } from '@/stores/project/executionContext'
import { entryMethodPointer } from '@/stores/suggestionDatabase/entry'
import {
entryMethodPointer,
makeArgument,
makeConstructor,
makeMethod,
makeStaticMethod,
} from '@/stores/suggestionDatabase/entry'
} from '@/stores/suggestionDatabase/mockSuggestion'
import { assert } from '@/util/assert'
import { Ast } from '@/util/ast'
import { expect, test } from 'vitest'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import {
import { MenuItem } from '@/components/shared/AgGridTableView.vue'
import { WidgetInput } from '@/providers/widgetRegistry'
import { SuggestionDb } from '@/stores/suggestionDatabase'
import { makeType } from '@/stores/suggestionDatabase/entry'
import { makeType } from '@/stores/suggestionDatabase/mockSuggestion'
import { assert } from '@/util/assert'
import { Ast } from '@/util/ast'
import { GetContextMenuItems, GetMainMenuItems } from 'ag-grid-enterprise'
Expand Down
4 changes: 2 additions & 2 deletions app/gui/src/project-view/stores/awareness.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Vec2 } from '@/util/data/vec2'
import { reactive } from 'vue'
import { Awareness as YjsAwareness } from 'y-protocols/awareness'
import type { StackItem } from 'ydoc-shared/languageServerTypes'
import { type ExternalId } from 'ydoc-shared/yjsModel'
import * as Y from 'yjs'

// === Public types ===
Expand All @@ -10,7 +10,7 @@ export type FileName = string

export interface UploadingFile {
sizePercentage: number
stackItem: StackItem
method: ExternalId
position: Vec2
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import {
makeModule,
makeStaticMethod,
makeType,
} from '@/stores/suggestionDatabase/entry'
} from '@/stores/suggestionDatabase/mockSuggestion'
import { Ast } from '@/util/ast'
import { unwrap } from '@/util/data/result'
import { tryIdentifier, tryQualifiedName } from '@/util/qualifiedName'
Expand Down
11 changes: 9 additions & 2 deletions app/gui/src/project-view/stores/graph/graphDatabase.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,14 @@ import {
} from '@/util/reactivity'
import * as objects from 'enso-common/src/utilities/data/object'
import * as set from 'lib0/set'
import { reactive, ref, shallowReactive, type Ref, type WatchStopHandle } from 'vue'
import {
reactive,
ref,
shallowReactive,
type DeepReadonly,
type Ref,
type WatchStopHandle,
} from 'vue'
import { type SourceDocument } from 'ydoc-shared/ast/sourceDocument'
import {
methodPointerEquals,
Expand Down Expand Up @@ -60,7 +67,7 @@ export class GraphDb {
/** TODO: Add docs */
constructor(
private suggestionDb: SuggestionDb,
private groups: Ref<Group[]>,
private groups: Ref<DeepReadonly<Group[]>>,
private valuesRegistry: ComputedValueRegistry,
) {}

Expand Down
4 changes: 2 additions & 2 deletions app/gui/src/project-view/stores/graph/imports.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { SuggestionDb } from '@/stores/suggestionDatabase'
import { SuggestionKind, type SuggestionEntry } from '@/stores/suggestionDatabase/entry'
import { Ast } from '@/util/ast'
import { MutableModule, parseIdent, parseIdents, parseQualifiedName } from '@/util/ast/abstract'
import { astToQualifiedName, MutableModule, parseIdent, parseIdents } from '@/util/ast/abstract'
import { unwrap } from '@/util/data/result'
import {
qnLastSegment,
Expand All @@ -24,7 +24,7 @@ export function recognizeImport(ast: Ast.Import): Import | null {
const all = ast.all
const hiding = ast.hiding
const moduleAst = from ?? import_
const module = moduleAst ? parseQualifiedName(moduleAst) : null
const module = moduleAst ? astToQualifiedName(moduleAst) : null
if (!module) return null
if (all) {
const except = (hiding != null ? parseIdents(hiding) : []) ?? []
Expand Down
Loading

0 comments on commit 77ca61f

Please sign in to comment.